hastype(z,radical) дает другой результат

Я совершенно сбит с толку этим.

Я заметил, что когда достигается процесс глубоко внутри одного из моих модулей, где исходный вызов был сгенерирован из командной строки, он работает правильно, чем когда тот же процесс достигается, когда поток вызовов исходит из другого процесса, который вызывается из команды линия.

Я обнаружил, что все сводится к этой одной строке. В отладчике вижу это

 if hastype(z,radical) then
    ...

Это дает false во втором случае и дает true при вызове в первом случае. Это должно дать true в обоих случаях.

В отладчике смотрю на z, говорит что имеет такое значение

        1/x*sqrt(x^2*u)

Теперь в команде отладчика, когда я набираю

        hastype(z,radical)

Это дает false. Но когда я ввожу фактическое значение u в команду:

       hastype(1/x*sqrt(x^2*u),radical)

Теперь он дает true!

Все локально для этого процесса:

dsolve_step:-dsolve_step_homog:-convert_to_homog := proc(f0, x, y, u)
local f, z, tmp;
   1   f := f0;
   2   f := subs(y = u*x,expand(f));
   3   for z in op(f) do
   4 !     if hastype(z,radical) then    ##<=======
   5           tmp := sqrt(collect(z^2,x));
   6           f := subs(z = tmp,f)
           end if
       end do;
   7   return simplify(f)
end proc

Поэтому я понятия не имею, почему hastype(z,radical) дает false, а hastype(1/x*sqrt(x^2*u),radical) дает true, когда z само по себе равно 1/x*sqrt(x^2*u).

И это происходит только тогда, когда я вызываю модуль, как в случае 2, описанном выше.

Как видите, все локально. z,f,tmp являются местными. Один и тот же вызов вышеуказанной функции выполняется в обоих случаях. Все входные данные одинаковы в обоих случаях.

Вот скриншоты фактической отладки:

Графика Mathematica

Теперь я проверяю

Графика Mathematica

Теперь я проверяю по типу показанное фактическое значение z

Графика Mathematica

Это похоже на проблему с областью видимости, которую я не могу понять, что это такое. Может быть, то, на что я смотрю, не то, чем кажется.

Опять же, тот же вызов работает нормально, когда я вызываю модуль из командной строки с другого рабочего листа.

Оба рабочих листа (случай 1 и случай 2) используют разные математические движки. (Я настроил Maple для запуска нового математического движка для каждого рабочего листа, чтобы быть в безопасности)

Я ищу любое предложение, почему это происходит. Вызывающий процесс во втором случае также не использует никаких глобальных переменных. Я всегда начинаю с чистого ядра (перезагружаю).

Любая подсказка, что происходит и что искать? Или что попробовать найти в чем проблема?

Клен 2018.1, виндовс 10.


Обновить

Я нашел проблему. Но я действительно думаю, что это ошибка в Maple.

Я обнаружил, что если я использую eval(z), то это работает во втором случае, например:

 if hastype(eval(z),radical) then   

Теперь я получаю правду:

Графика Mathematica

Я не понимаю, зачем мне нужно добавлять туда eval(), поскольку Maple должен автоматически оценивать z до его значения при использовании for z in op(f) do, а затем ссылаться на z внутри цикла.

Итак, мой вопрос изменился на: Зачем здесь нужно eval()?

В любом случае, у меня есть обходной путь для этого. Но это не имеет смысла для меня сейчас.

convert_to_homog:=proc(f0,x,y,u)
  local f,z,tmp;
  f:=f0;
  f:=subs(y=u*x,expand(f));

  #this below can give wrong answer sometimes. It tries to 
  #change 1/X*sqrt(x^2) to  sqrt(1)
  #by moving x under the sqrt. But this is valid only when x>0
  # i..e   1/x => sqrt(1/x^2)  only when x>0
  #keep it for now, until I implement exact solver.

  for z in op(f) do
      if hastype(eval(z), radical)  then
         tmp:=sqrt(collect(z^2,x));
         f:=subs(z=tmp,f);
      fi;
  od;
  return(simplify(f));

end proc;

person Nasser    schedule 18.08.2018    source источник


Ответы (1)


Ключевым моментом здесь является то, что (как показано вами) значение z включает неоцененный вызов sqrt, а не что-то для питания 1/2.

Невычисленный вызов sqrt не относится к типу radical, хотя то, что он оценивает, относится к этому типу.

Во-первых, давайте разберемся с таким невычисленным вызовом sqrt на верхнем уровне (т.е. не внутри тела какой-либо процедуры). Сначала мы присваиваем имени z выражение, содержащее неоцененный вызов sqrt.

Мы протестируем тип одноуровневой оценки имени z, а также полную оценку имени z.

restart;
z := '1/x*sqrt(x^2*u)';

                           2
                     sqrt(x  u)
                z := ----------
                         x

Оценка 1-го уровня z дает его значение, но без какой-либо другой оценки. Вызов sqrt остается неоцененным.

eval(z, 1); # 1-level evaluation

                         2
                   sqrt(x  u)
                   ----------
                       x

Необработанный вызов sqrt не из type radical.

hastype(eval(z, 1), radical);

                     false

Теперь вот полная оценка z, которая является поведением по умолчанию на верхнем уровне.

eval(z); # full evaluation      

                     2   1/2
                   (x  u)
                   ---------
                       x

z;

                         2   1/2
                   (x  u)
                   ---------
                       x

Передача z в hastype теперь передает полную оценку hastype. То есть выражение, переданное в hastype, теперь содержит что-то, усиливающее 1/2, и оно распознается как type radical.

hastype(z, radical);         

                     true

Теперь прочтите это из маркированного списка. в разделе "Правила оценивания" на странице помощи по ТЕМЕ proc,

"Within a procedure, during the execution of its
 statementSequence, local variables have single level
 evaluation. This means that using a variable in an
 expression will yield the current value of that variable,
 rather than first evaluating that value."

Давайте рассмотрим аналогичный вышеприведенному пример, но внутри процедуры.

Во-первых, мы будем иметь дело с z в процедуре. Как и ранее, имени z присваивается выражение, содержащее невычисленный вызов sqrt. В отличие от поведения верхнего уровня, в рамках процедуры назначенный локальный z оценивается только на уровне 1.

restart;

f := proc( f0 )       
  local z;
  lprint( f0 );
  z := f0;
  lprint( z );
  hastype(z, radical);
end proc:

f( '1/x*sqrt(u*x^2)' );

1/x*sqrt(u*x^2)
1/x*sqrt(u*x^2)
                     false

А теперь мы изменим процедуру, чтобы иметь дело с eval(z), которая получает выражение, содержащее что-то для мощности 1/2.

restart;              

f := proc( f0 )        
  local z;             
  lprint( f0 );        
  z := f0;             
  lprint( eval(z) );   
  hastype(eval(z), radical);
end proc:                   

f( '1/x*sqrt(u*x^2)' );     

1/x*sqrt(u*x^2)
1/x*(u*x^2)^(1/2)
                     true

Таким образом, похоже, что вы испытываете задокументированное и предполагаемое поведение для оценки назначенных локальных переменных в процедуре. Это не ошибка.

Вы предоставили только фрагмент кода и не показали, какие именно аргументы f0, x, y, u передаются процедуре convert_to_homog. Но вы показали, что локальное z равно 1/x*sqrt(x^2*u), а не 1/x*(x^2*u)^(1/2), и если это правда, то hastype(z,radical) возвращает false не ошибка.

С вашей текущей настройкой, да, вы можете передать eval(z) в hastype и получить ожидаемый результат true.

Но, возможно, вам также следует пересмотреть, почему z в первую очередь присваивается невычисленное выражение. Это преднамеренно или из-за случайного программирования ранее?

person acer    schedule 20.08.2018
comment
Спасибо. Для меня в новинку то, что локальные переменные в процедуре не полностью оцениваются при ссылке. Это очень усложняет программирование в Maple, если нужно выполнить eval(var) вокруг каждой локальной переменной, чтобы убедиться, что она полностью оценена. Код также теперь будет выглядеть уродливо, так как мне придется оборачивать каждую переменную с помощью eval(). Для меня это не имеет смысла, почему Maple делает это для локальных переменных в процедуре. Я ожидал, что когда я ссылаюсь на переменную, то используется полное оцененное значение.... - person Nasser; 20.08.2018
comment
But perhaps you should also re-examine why z is being assigned the unevaluated expression in the first place Ну, как видно из кода. Я передал f0 процедуре, которой назначена локальная переменная f, поэтому я могу ее изменить. Затем использовал f позже в цикле. Таким образом, sqrt было в выражении f0, идущем по цепочке вызовов. Трудно опубликовать полный пример кода, показывающий все вызовы, так как он слишком длинный. Но теперь я понимаю разницу между оценкой локальных переменных. Я должен больше думать об этом. Для меня это делает программирование на Maple очень сложным. - person Nasser; 20.08.2018
comment
Ваша главная проблема здесь, похоже, заключается в том, что вы предотвращаете оценку f0, переданную в процедуру, где-то ранее. Вы можете понять, где это происходит и почему. Не обязательно имеет смысл обвинять модель оценки Maple в (даже непреднамеренном) неправильном предыдущем коде. Возможно, это из-за parse без eval. Или (частично) в сочетании с использованием subs или subsindets, когда eval или evalindets подошли бы лучше. Мы не можем видеть весь ваш код. - person acer; 20.08.2018
comment
Я могу попробовать сделать MWE. Исходные выражения f0 в данном случае являются выражениями Maple. Они читаются из простого текстового файла как строки. Я читаю каждое выражение из файла в виде строки, использую для них parse, чтобы преобразовать их в фактическое выражение клена, чтобы я мог их использовать, а затем передаю их в указанный выше процесс для обработки. поэтому sqrt() было то, как исходное выражение/строка Maple было в прочитанном файле. Я изменю свой код, чтобы применить eval к результату parse, когда я впервые прочитаю файл и посмотрю, изменит ли это ситуацию и решит ли эту проблему. Спасибо. - person Nasser; 20.08.2018