Имена переменных в расширении генерации кода Maple

Я хочу расширить Maple CodeGeneration[C] обработчиком кусочной функции (не знаю, почему она не включена). С этой целью я сделал:

with(CodeGeneration):
with(LanguageDefinition):

LanguageDefinition:-Define("NewC", extend="C",
    AddFunction("piecewise", anything::numeric,
        proc()
            local i;
            Printer:-Print("if(",_passed[1],"){",_passed[2],"}");
            for i from 3 to _npassed-2 by 2 do
                Printer:-Print("else if(",_passed[i],"){",_passed[i+1],"}");
            end do;
            Printer:-Print("else{",_passed[_npassed],"}");
        end proc,
    numeric=double)
);

Обратите внимание, что я использую операторы if else вместо операторов case по назначению. Вот пример кода для перевода:

myp:=proc(x::numeric)
    piecewise(x>1,1*x,x>2,2*x,x>3,3*x,0);
end proc:
Translate(myp, language="NewC");

Выход

void myp (double x)
{
    if(0.1e1 < x){x}else if(0.2e1 < x){0.2e1 * x}else if(0.3e1 < x){0.3e1 * x}else{0};
    ;
}

Для правильной C-программы мне, очевидно, нужно заменить фигурные скобки, например

{x}

чем-то вроде

{result=x;}

и аналогично для остальных. Я мог бы сделать это вручную, изменив строки в приведенном выше операторе AddFunction. Но тогда имя переменной result не известно генератору кода, поэтому не будет никакого объявления, и значение результата не будет возвращено по мере необходимости для соответствия подпрограмме myp или любой более сложной процедуре, в которой результат кусочного может быть назначен к какой-либо другой переменной или используемой в вычислениях. Итак, как правильно обработать это в подпрограммах CodeGeneration? т.е. как я могу получить действительное имя переменной и т. д.


person highsciguy    schedule 08.04.2012    source источник


Ответы (1)


Как насчет чего-то подобного?

restart:

with(CodeGeneration):
with(LanguageDefinition):

LanguageDefinition:-Define("NewC", extend="C",
    AddFunction("piecewise", anything::numeric,
        proc()
            local i;
            Printer:-Print("( (",_passed[1],") ? ",_passed[2]);
            for i from 3 to _npassed-2 by 2 do
                Printer:-Print(" : (",_passed[i],") ? ",_passed[i+1]);
            end do;
            Printer:-Print(" : ",_passed[_npassed]," ) ");
        end proc,
    numeric=double)
);

myp:=proc(x::numeric) local result::numeric;
    result := piecewise(x>3,3*x,x>2,2*x,x>1,1*x,0);
end proc:

Translate(myp, language="NewC");

double myp (double x)
{
  double result;
  result = ( (0.3e1 < x) ? 0.3e1 * x : (0.2e1 < x) ? 0.2e1 * x : (0.1e1 < x) ? x : 0 ) ;
  return(result);
}

[отредактировано, чтобы добавить материал ниже]

Оказывается, CodeGeneration[C] обрабатывает piecewise, но только если указана опция optimize. (Я отправлю отчет об ошибке, что он должен обрабатываться по умолчанию.)

restart:

with(CodeGeneration):
with(LanguageDefinition):
myp:=proc(x::numeric) local result::numeric;
     result:=piecewise(x>3,3*x,x>2,2*x,x>1,1*x,0);
end proc;

         myp := proc(x::numeric)
         local result::numeric;
           result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0)
         end proc;

Translate(myp, language="C", optimize);

double myp (double x)
{
  double result;
  double s1;
  if (0.3e1 < x)
    s1 = 0.3e1 * x;
  else if (0.2e1 < x)
    s1 = 0.2e1 * x;
  else if (0.1e1 < x)
    s1 = x;
  else
    s1 = 0.0e0;
  result = s1;
  return(result);
}

Как видите, выше piecewise обрабатывается путем перевода в отдельный блок if(){..} с присвоением введенной временной переменной. Это временное значение впоследствии используется везде, где существует вызов piecewise в процедуре Maple. А временное объявлено. Красивый и автоматический. Так что этого может быть достаточно для использования вами piecewise.

Вы также спросили, как вы можете вводить и объявлять такие временные переменные в своих собственных расширениях (если я правильно вас понимаю). Продолжая ту же сессию Maple сверху, вот несколько идей в этом направлении. Генерируется неназначенное глобальное имя. Процедура myp приводится в инертную форму, к которой добавляется новая локальная переменная. И затем эта измененная инертная форма снова превращается в настоящую процедуру. В качестве иллюстрации я использовал модифицированную версию исходного расширения для обработки piecewise. Все это дает что-то близкое к приемлемому. Единственная загвоздка в том, что оператор присваивания,

result = temporary_variable;

не к месту! Он находится перед блоком перевода piecewise. Я еще не вижу, как исправить это в методе.

LanguageDefinition:-Define("NewC", extend="C",
    AddFunction("piecewise", anything::numeric,
        proc()
            global T;
            local i, t;
            t:=convert(T,string);
            Printer:-Print(t,";\n");
            Printer:-Print("  if (",_passed[1],
                           ")\n    { ",t," = ",_passed[2],"; }\n");
            for i from 3 to _npassed-2 by 2 do
                Printer:-Print("  else if (",_passed[i],")\n    { ",
                               t," = ",_passed[i+1],"; }\n");
            end do;
            Printer:-Print("  else { ",t," = ",_passed[_npassed],"; }");
        end proc,
    numeric=double)
):

T:=`tools/genglobal`('s'):

newmyp := FromInert(subsindets(ToInert(eval(myp)),'specfunc(anything,_Inert_LOCALSEQ)',
           z->_Inert_LOCALSEQ(op(z),
                              _Inert_DCOLON(_Inert_NAME(convert(T,string)),
                                            _Inert_NAME("numeric",
                                               _Inert_ATTRIBUTE(_Inert_NAME("protected",
                                               _Inert_ATTRIBUTE(_Inert_NAME("protected")
          ))))))));

             newmyp := proc(x::numeric)
             local result::numeric, s::numeric;
               result := piecewise(3 < x, 3*x, 2 < x, 2*x, 1 < x, x, 0)
             end proc;

Translate(newmyp, language="NewC");

double newmyp (double x)
{
  double result;
  double s;
  result = s;
  if (0.3e1 < x)
    { s = 0.3e1 * x; }
  else if (0.2e1 < x)
    { s = 0.2e1 * x; }
  else if (0.1e1 < x)
    { s = x; }
  else { s = 0; };
  return(result);
}

Если вы повторно запустите последние три оператора выше (от присваивания T до вызова Translate), вы должны увидеть новую используемую временную переменную, такую ​​как s0. И затем s1, если повторяется еще раз. И так далее.

Возможно, это даст вам еще несколько идей для работы. Ваше здоровье.

person acer    schedule 10.04.2012
comment
Это работает, конечно, и, вероятно, является лучшим решением для кусочной функции. Но что я могу сделать в общем случае, когда мне нужно выполнить некоторые промежуточные вычисления для вычисления функции на языке C? Как я могу получить допустимые имена переменных? - person highsciguy; 10.04.2012