Post Reply 
Creating an equation library (Updated 03-FEB-2017)
01-27-2017, 05:47 PM
Post: #46
RE: Creating an equation library (updated)
Nothing like a nearly-year-long delay between a post and a response... but I finally had some time to get back to this project. This time, however, I am approaching it from the "other end" (i.e. interface).

Since we now have access to app files and app variables, it is easier (not really) to manage equations and variables from a programmer's point of view. The code below does nothing other than create an app for us to create systems of equations and save it in a library.

If you copy the buit-in Solve app, and paste the code below into the copied app (I called it Equation Library, but you can use whatever name you want), then it should be ready to go. The app starts off by looking for an app file named "Equation Library.lib" which is supposed to be a list containing different systems of equations. If you don't have such a file, it will make one for you. Each system is itself a list consisting of a name, equations, variables, and the descriptions of the variables. You can use the [View] key to get more options such as adding another page of equations (since the Symb view only shows 10 at a time).

To create a new system, start by creating your variables. Press [View] and select Add/Edit variables. Enter in a variable name and a description for the variable. Once your variables are created, you can start creating your equations. Save your system using [View]. Missing features are deletion (of variables, and of systems); that will come once we build a UI for browsing the list of systems.

I am hoping to finally put everything together (the solver engine) so that this becomes a full blown equation library complete with solver and "file manager" to manage your various systems.

In the meantime, people can play around with the code below if they want to start building their libraries. For those who do not speak English, the code is prepared in a way that should easily port to other languages (all the text are at the top of the source with the only exceptions being the [View] menu options).

PHP Code:
ssVersion:="Equation Library 0.01 by Han Duong";

// colors
ssFG:=#0h;
ssBG:=#FFFFFFh;
ssR:=#FF0000h;
ssG:=#FF00h;
ssB:=#FFh;


// error messages
ssInvDat:="Invalid library data.";
ssNoDat:="Unable to locate library data.";
ssNullName:="Null name not allowed.";
ssInvName:="Invalid name.";
ssAbort:="Operation aborted; improper initialization.";
ssBadVar:="Conflict with existing variable:\n";
ssSubmitBug:="This should never happen!\nPLease submit bug report.";
ssNotEqn:="Non-equation on page ";
ssNonVar:="No such var. on page ";
ssNoLibDat:="No library data found.\nCreating empty library and empty\ninitial system.";
ssEOW:="Overwrite disabled and name already exists:\n";
ssNotSaved:="SAVE CANCELED!";


// app messages
ssTNewVar:="Create/Edit Variable";
ssLName:="Name:";
ssLDescr:="Description:";
ssLOWrite:="Overwrite";
ssHName:="Enter the variable name";
ssHDescr:="Enter a description for the variable";
ssHOWrite:="Overwrite if variable already exists?";
ssTSaveSys:="Save Current System";
ssHSysName:="Enter a name for the system.";
ssLEqns:="Eqns:";
ssLVars:="Vars:";
ssHEqns:="Verify equations in system.";
ssHVars:="Verify variables for system.";
ssTNewSys:="New System";

ssTSettings:="Equation Library Settings";
ssLSaving:="When switching systems, always";
ssCSaving:={ "prompt to save""save automatically""discard all changes"};
ssHSaving:="Select default save behavior";


// misc
ssVLoadEqns:="Populating equations in Symb view...";
ssVLoadVars:="Setting up equation variables...";
ssVCheckVars:="Verifying variables in system...";
ssVCheckLibDat:="Verifying library data...";
ssVUpdateEqns:="Equations modified; updating lib data...";
ssVUpdateVars:="Variables modified; updating lib data...";
ssVNoEqns:="(No equations)";
ssVNoVars:="(No variables)";
ssVVarMade:="Created variable: ";


// View menu options
ssTSEP:="Select Equations Page";
ssTSelPage:="Select New Page";
ssTNewPage:="Create New Page";


ssMsgRow;
export ssInit;
ssLibFN;
export ssCurSys;
export ssCurSysIndex;
export ssCurLib;
ssLibSize;
export ssSysTitles;
ssVarKey:="SSVersion";
export ssEqPages;
export ssEqPage;
export ssNullSys;


// DO NOT MODIFY BELOW HERE

ssUpdateSys()
begin
  local n
;
  
local eq:="";
//  for n from 0 to 9 do
//    eq:="E" + string(n,1,0) + ":=" + string("");
//    expr(eq);
//  end;
  
if ssLibSize then
    ssSysTitles
:=makelist(ssCurLib(I,1),I,1,ssLibSize);
  else
    
ssSysTitles:={};
  
end;
  
ssEqPages:={1,10};
  
n:=size(ssCurSys(2));
  
ssNullSys:=NOT(n);
  
ssEqPages(1):=ip((n-1)/10);
  
ssEqPages(2):=(n-1mod 10;
  
ssEqPage:=0;
  
DelAVars(AVars);
end;



ssInitSSApp()
begin
  
if ssInit then return; end;

  
ssLibFN:="Equation Library.lib";
  
ssVarKey:="SSVersion";
  
iferr
    ssCurLib
:=AFiles(ssLibFN);
  
then
    msgbox
(ssNoLibDat);
    
ssCurLib:={ { ssTNewSys, {}, {}, {}, {}, {}, {} } };
    
AFiles(ssLibFN):=ssCurLib;
  
end;
  
ssCurSysIndex:=1;
  
ssCurSys:=ssCurLib(1);
  
ssLibSize:=size(ssCurLib);
  
ssUpdateSys();
  
ssInit:=1;
end;


ssPrint(msg)
begin
  textout_p
(msg,0,10*ssMsgRow,1,ssFG,320,ssBG);
  
ssMsgRow:=(ssMsgRow+1mod 20;
end;


ssError(msg)
begin
  textout_p
(msg,0,10*ssMsgRow,1,ssR,320,ssBG);
  
ssMsgRow:=(ssMsgRow+1mod 20;
end;


ssCheckType(list,t)
begin
  local n
:=size(list);
  if 
n then
    
if type(list(n))<>t then return(1); end;
  else
    return(
1);
  
end;
  return(
0);
end;



//******************************************
// Library Data format
// { sys1, sys2, ... , sysN }
//
// Each sys (system) is a list of the form
// {
//   "Title",
//   { "eq1", "eq2", ... },
//   { sel1, sel2, ... },
//   { "var1", "var2", ... },
//   { "des1", "des2", ... },
//   { val1, val2, ... },
//   { con1, con2, ... }
// }
//
// eq  = equation
// sel = 0 or 1 for selection of corresponding
//       equation in the system
// var = variable
// des = description of variable
// val = value of corresponding variable
// con = 0 or 1 for whether var is constant
//
// returns 0 if error or 1 if OK
//******************************************
export ssCheckLibDat()
begin

  ssPrint
(ssVCheckLibDat);
  
ssInitSSApp();

  
local syseqs,j,k;
  
local libisbad:=0;
  
local types:={2,2,0,2,2,0,0};

  
iferr
    
if ssLibSize then
      
for j from 1 to ssLibSize do
        
lib:=ssCurLib(j);
        if 
type(lib)<>6 then
          ssError
(ssInvDat); return(0);
        else
          
k:=size(lib);
          if (
k<1) OR (k>7then
            ssError
(ssInvDat); return(0);
          
end;
          for 
k from 2 to 7 do
            if 
type(lib(k))<>6 then
              ssError
(ssInvDat); return(0);
            
end;
            if 
ssCheckType(lib(k),types(k)) then
              ssError
(ssInvDat); return(0);
            
end;
          
end// for k
        
end// if type(lib)
      
end// for j
    
end// if ssLibSize
  
then
    ssError
(ssNoDat); return(0);
  
end;
  return(
1);
end;


// initialize variables
ssInitVars()
begin

  local varslist
:=ssCurSys(4);
  
local valslist:=ssCurSys(6);
  
local n:=size(varslist);
  
local j,tmp,varval;


  
iferr
    
if (AVars(ssVarKey) == ssVersionthen   
      
return;
    
end;
  
then
    
// nop
  
end;

  
ssPrint(ssVLoadVars);
  for 
j from 1 to n do
    
varval:=CAS(eval(varslist(j)));
    
tmp:="purge(" varslist(j) + ")";
    
CAS(eval(tmp));
    if (
CAS(eval(varslist(j))) <> 8then
      msgbox
(ssBadVar+varslist(j));
    
end;
    if ( (
type(varval) == 0) OR (type(varval) == 3) ) then
      AVars
(varslist(j)):=varval;
    else
      
AVars(varslist(j)):=valslist(j);
    
end;
  
end;
  
AVars(ssVarKey):=ssVersion;

end;


// checks to see if AVars and system of equations
// vars match; excludes version key
export ssCheckVars()
begin

  ssPrint
(ssVCheckVars);
  
ssInitSSApp();
  
ssInitVars();

  
local j,n;
  
local avarlist:=AVars();
  
local varlist:=ssCurSys(4);
  
n:=size(varlist);
  if (
n+<> size(avarlist)) then
    
return(0);
  
end;

  for 
j from 1 to n do
    if (
pos(avarlist,varlist(j)) == 0then return(0); end;
  
end;

  
n:=size(avarlist);
  for 
j from 1 to n do
    if ((
avarlist(j) <> ssVarKey) AND (pos(varlist,avarlist(j)) == 0)) then
      
return(0);
    
end;
  
end;
  return(
1);

end;


// do we have any equations
//  1: yes, equations in symb view
//  0: no equations at all
// -1: yes, but only saved in library
ssHaveEqns()
begin
  local j
;
  for 
j from 0 to 9 do
    if 
ISCHECK(jthen return(1); end;
  
end;

  if (
ssCurSysIndex == 0then return(0); end;

  if (
type(ssCurSys) <> 6then return(0); end;

  if 
size(ssCurSysthen
    
if size(ssCurSys(2)) then
      
return(-1);
    else
      return(
0);
    
end;
  else
    return(
0);
  
end;
end;


// UI for creating new variables
ssCreateVar()
begin
  local run
:=1;
  
local n;
  
local varname:=""varinfo:="";
  
local ow:=0;

  
ssInitSSApp();
  
ssInitVars();

  while 
run do
    if 
input(
      {
        {
varname, [2], {30650}},
        {
varinfo, [2], {30651}},
        {
ow1, {30,10,2}}
      },
      
ssTNewVar,
      { 
ssLNamessLDescrssLOWrite },
      { 
ssHNamessHDescrssHOWrite }
    )
    
then

      
if size(varname)<1 then
        msgbox
(ssNullName);
      else
        
n:=pos(AVars,varname);
        if 
n then
          
if ow then
            n
:=pos(ssCurSys(4),varname);
            
ssCurSys(5,n):=varinfo;
            
run:=0;
          else
            
msgbox(ssEOW varname);
          
end;
        else
          
iferr 
            AVars
(varname):=0;
          
then
            msgbox
(ssInvName);
          else
            
ssCurSys(4,0):=varname;
            
ssCurSys(5,0):=varinfo;
            
ssCurSys(6,0):=0;
            
ssCurSys(7,0):=0;
            
msgbox(ssVVarMade varname);
            
varname:=""varinfo:="";
//            run:=0;
          
end;
        
end;
      
end// end null name

    
else
      
run:=0;
    
end;

  
end// end while
end;


// save current equations
ssSaveEqns()
begin
  local j
,k,n1,n2;
  
local cmd:="";
  
local oldeqn:="";
  
local neweqn:="";
  
local markadd:=0;
  
local neweqns:={};
  
local teqnlist:={};
  
local tsellist:={};

  if 
ssCheckVars() then

    ssPrint
(ssVLoadEqns);
    
n1:=ssEqPage*10+1;
    if (
ssEqPage ssEqPages(1)) then
      n2
:=n1+9;
    else
      
n2:=n1+ssEqPages(2);
    
end;

    for 
j from n1 to n2 do
      
k:= j mod 10;
      
cmd:="string(E" string(k,1,0) + ",1,12)";

      
iferr
        neweqn
:=expr(cmd);
      
then
        neweqn
:="";
      else
        if 
ssNullSys then
          oldeqn
:="";
        else
          
cmd:="E" string(k,1,0) + ":=" string(ssCurSys(2,j));
          
iferr expr(cmd); then end;
          
cmd:="string(E" string(k,1,0) + ",1,12)";
          
iferr oldeqn:=expr(cmd); then end;
        
end;
        if (
oldeqn <> neweqnthen
          
if ssNullSys then
            ssCurSys
(2,0):=neweqn;
          else
            
ssCurSys(2,j):=neweqn;
          
end;
        
end;
      
end;

      
cmd:="E" string(k,1,0) + ":=" string(neweqn);
      
iferr expr(cmd); then
        
// msgbox(ssSubmitBug);
      
end;

      if 
ISCHECK(kthen
        ssCurSys
(3,j):=1;
      else
        
ssCurSys(3,j):=0;
      
end;

      if (
size(neweqn) == 0then
        ssCurSys
(3,j):=-1// mark for delete
      
end;
    
end;  // end for j

    
n2:=n1+9;
    for 
k from j to n2 do
      
n1:=k mod 10;
      
cmd:="string(E" string(n1,1,0) + ",1,12)";
      
iferr
        neweqn
:=expr(cmd);
      
then
        
// nop
      
else
        if 
size(neweqnthen
          neweqns
(0):=neweqn;
          
neweqns(0):=ISCHECK(n1);
          
markadd:=1;
        
end;
      
end;
    
end// end for k

    // rebuilt existing equations
    
k:=0;
    
n2:=size(ssCurSys(2));
    for 
j from 1 to n2 do
      if (
ssCurSys(3,j) >= 0then
        teqnlist
(0):=ssCurSys(2,j);
        
tsellist(0):=ssCurSys(3,j);
        
k:=k+1;
      
end;
    
end;
    
ssCurSys(2):=teqnlist;
    
ssCurSys(3):=tsellist;

    if 
markadd then
      n2
:=size(neweqns)/2;
      for 
j from 1 to n2 do
        
ssCurSys(2,0):=neweqns(2*j-1);
        
ssCurSys(3,0):=neweqns(2*j);
        
k:=k+1;
      
end;
    
end;

    
ssEqPages(1):=ip((k-1)/10);
    
ssEqPages(2):=(k-1mod 10;
    
ssEqPage:=min(max(0,ssEqPage),ssEqPages(1));

    if 
k then
      ssNullSys
:=0;
    else
      
ssNullSys:=1;
    
end;

    return(
1);

  else
    
msgbox(ssAbort);
    return(
0);
  
end;
end;


// set up equations in Symb view
export ssLoadSymb()
begin

  local j
,k,n1,n2;
  
local cmd:="";

  
// no equations to populate Symb view?
  
if ssNullSys then 
    
for j from 0 to 9 do
      
cmd:="E" string(j,1,0) + ":=" string("");
      
expr(cmd);
    
end;
    return(
1);
  
end;

  
ssPrint(ssVLoadEqns);
  
n1:=ssEqPage*10+1;
  if (
ssEqPage ssEqPages(1)) then
    n2
:=n1+9;
  else
    
n2:=n1+ssEqPages(2);
  
end;
  for 
j from n1 to n2 do
    
k:= j mod 10;
    
cmd:="E" string(k,1,0) + ":=" string(ssCurSys(2,j));
    
iferr expr(cmd); then end;
    if (
ssCurSys(3,j)==1then CHECK(k); else UNCHECK(k); end;
  
end;

  
n2:=n1+9;
  for 
k from j to n2 do
    
n1:=k mod 10;
    
cmd:="E" string(n1,1,0) + ":=" string("");
    
expr(cmd);
  
end;

  return(
1);

end;


// select an equations page
ssSelectEqPage()
begin
  ssInitSSApp
();
  
local j;
  
local n:=ssEqPages(1)+1;
  
local page:=ssEqPage+1;
  
local curpage:=page;
  
local pagelist:={};
  
local title:="[" string(page,1,0) + "/" string(ssEqPages(1)+1,1,0) + "] " ssTSelPage;
  
  
pagelist:=makelist(j,j,1,n);
  
pagelist(0):=ssTNewPage;

  if 
choose(page,title,pagelistthen

    
if (curpage <> pagethen
      ssSaveEqns
(); 

      if (
page == (n+1)) then

        
if (ssNullSys == 0then 
          ssEqPages
(1):=n+1;

          
// fill last page
          
if (ssEqPages(2) < 9then
            n
:=9-ssEqPages(2);
            for 
j from 1 to n do
              
ssCurSys(2,0):="";
              
ssCurSys(3,0):=-1// mark for deletion
            
end;
          
end;
        
end;

        
// create new page
        
for j from 1 to 10 do
          
ssCurSys(2,0):="";
          
ssCurSys(3,0):=-1// mark for deletion
        
end;

        
n:=size(ssCurSys(2));
        
ssEqPage:=ip((n-1)/10);
        
ssEqPages(1):=ssEqPage;
        
ssEqPages(2):=(n-1mod 10;
        
ssNullSys:=0;

      else

        
// not creating new blank page
        
ssEqPage:=min(max(0,page-1),ssEqPages(1));

      
end// if newpage or existing page

    
end// if selpage <> page

    
ssLoadSymb();

  
end// if choose
end;


// set new system
export ssSetNewSys(n)
begin
  
if (== ssCurSysIndexthen
    
return(1);
  
end;

  if (
ssLibSizethen
    
return(0);
  
end;

  
ssCurSysIndex:=n;
  
ssCurSys:=ssCurLib(n);
  
ssUpdateSys();
  
ssInitVars();
  
ssLoadSymb();
end;


ssErrorPage(n,msg,eqn)
begin
  local p
:=ip((n-1)/10)+1;
  
msgbox(msg ":\n" eqn);
end;


// check if equations are valid
// assumes equations have been saved
export ssCheckEqns()
begin
  local n
:=size(ssCurSys(2));
  
local eqn:="";
  
local j,k,v;
  
local varlist:={};

  if 
n then

    
// check each equation
    
for j from 1 to n do
      
eqn:=ssCurSys(2,j);

      
// do we have = symbol?
      
if instring(eqn,"="then
        iferr eqn
:=string(E0,1,12); then eqn:=""end;
        
E0:=ssCurSys(2,j);
        
varlist:=LNAME(E0);
        
v:=size(varlist);
        if 
v then
          
for k from 1 to v do
            if (
pos(ssCurSys(4),string(varlist(k))) == 0then
              ssErrorPage
(j,ssNonVar,ssCurSys(2,j)+"\n> "+varlist(k));
              return(
0);
            
end;
          
end;
        else
          
// constants only? not equation
          
ssErrorPage(j,ssNotEqn,ssCurSys(2,j));
          return(
0);       
        
end;
        
iferr E0:=eqnthen end;
        return(
1);
        
      else
        
// no equal symbol; report page
        
ssErrorPage(j,ssNotEqn,eqn);
        return(
0);
      
end;
    
end;

  else
    
// no equations to check
    
return(1);
  
end;
end;


// save current system
// no null names but does not check
// if name is all spaces
ssSaveSystem()
begin
  local sysname
:=ssCurSys(1);
  
local eqns:=ssCurSys(2);
  
local vars:=ssCurSys(4);
  
local eqn,var,n;
  
local run:=1;

  
// bug in input when choose lists are empty
  
if (size(eqns) < 1then eqns:={ ssVNoEqns }; end;
  if (
size(vars) < 1then vars:={ ssVNoVars }; end;


  while 
run do
    if 
input(
      {
        { 
sysname, [2], { 1575} },
        { 
eqneqns, { 1575} },
        { var, 
vars, { 1575} }
      },
      
ssTSaveSys,
      { 
ssLName,    ssLEqnsssLVars },
      { 
ssHSysNamessHEqnsssHVars }
    )
    
then

      
if size(sysnamethen
        
// maybe later add check for dupes
        
n:=pos(ssSysTitlessysname);

        if 
ssCheckEqns() then
          ssCurSys
(1):=sysname;
          
ssCurLib(ssCurSysIndex):=ssCurSys;
          
AFiles(ssLibFN):=ssCurLib;
        else
          
msgbox(ssNotSaved);
        
end;
        
run:=0;

      else
        
msgbox(ssNullName);
      
end;

    else
      
// user canceled
      
msgbox(ssNotSaved);
      
run:=0;
    
end;

  
end// end while;
end;


// create a system
ssNewSystem()
begin
  ssCurSys
:={ssTNewSys, {}, {}, {}, {}, {}, {} };
  
ssCurLib(0):=ssCurSys;
  
ssCurSysIndex:=ssCurSysIndex 1;
  
ssLibSize:=ssLibSize 1;
  
ssUpdateSys();
  
ssInitVars();
  
ssLoadSymb();
  
startview(0,1);
end;



START()
begin
//  startview(-1,1);
  
ssInitSSApp();
  
ssInitVars();
  
ssLoadSymb();
  
startview(0,1);
end;


Symb()
begin
  ssSaveEqns
();
  
ssLoadSymb();
  
startview(0,1);
end;


// select equations page (View Menu)
view "Select Page"ssMenuEqnPage()
begin
  ssSelectEqPage
();
  
startview(0,1);
end;


// UI for creating new variables (View Menu)
view "Add/Edit Variable"ssMenuNewVar()
begin
  ssCreateVar
();
end

// reload saved equations (View Menu)
view "Restore Equations"ssMenuLoadEqns()
begin
  ssLoadSymb
();
  
startview(0,1);
end;


// save current system (View Menu)
view "Save System"ssMenuSaveSys()
begin
  ssSaveEqns
();
  
ssSaveSystem();
end;

// create new system (View Menu)
view "New System"ssMenuNewSys()
begin
  ssNewSystem
();
end

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-27-2017 05:47 PM



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