Skip to content

Instantly share code, notes, and snippets.

@fakuivan
Last active September 29, 2019 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fakuivan/c88588ed146db7e848238e6c7a82cdae to your computer and use it in GitHub Desktop.
Save fakuivan/c88588ed146db7e848238e6c7a82cdae to your computer and use it in GitHub Desktop.
HP Prime CAS "programs" I made to solve multivariable calculus, statistics and physics 2 exercises

engineer.exe

These are scripts I use to serialize some of the practice exercises we get on multivariable calculus, statistics and physics 2 class, they are not meant to be easy to understand or a tutorial on how to write CAS programs on the HP Prime graphing calculator but rather a set of solutions I was able to come up with, for some a valuable resource nonetheless.

Calculus 2

Multivariable Taylor series

I used to have a more complicated method for solving this, luckily multivariable Taylor series expansion is already implemented natively. You can find more info about the previous method here.

par={f=sin(x+y), v={x,y}, p=[1,1], ord=5}
series(f(par),v(par),p(par),ord(par))

Maxima and minima

This program builds a list with the format {{[solution point 1],[eigenvalues for the hessian matrix on that point]}, ..} used to analyze maxima and minima of f

par={f=2*x^3+15*y^3–9*x*y, v={x,y}}
apply((p)->{p,EIGENVAL((hessian(f(par),v(par)))((v(par)) = p))},solve((grad(f(par),v(par))) = (makelist(0,x,0,size(v(par)))),v(par)))

Lagrange multipliers

Finds the minima/maxima and lambda values for f restrited by the functions defined in r

par = {f = (sqrt(x^2+y^2+5)),v = {x,y},l = {l1},r = {(x-1)^2+y^2-1}}
solve((grad(f(par)+dot(l(par),r(par)),concat(v(par),l(par))))=(makemat(0,size(concat(v(par),l(par))))),concat(v(par),l(par)))

Iterated integrals

This CAS function takes a function as the first argument, a list of integration variables as the second, and a list of lists as the third containing two elements interpreted as the lower and upper integration limits respectively, the order of said lists should follow the order of the previous argument. function, {var1, var2, ...}, {{var1_lim1, var1_lim2}, {var2_lim1, var2_lim2}, ...}

#cas
iint(function_, vars_, limits_):= begin
  local gint_, index_, size_, result_;
  gint_ := 'int';
  result_ := function_; 
  size_ := min(size(vars_), size(limits_));
  for index_ from 1 to size_ do
    result_ := gint_(result_,
                     vars_[index_], 
                     limits_[index_](1), 
                     limits_[index_](2));
  end;
  return result_;
end;
#end

Graphing 2D integration limits

I've been messing around with this for far too long, but I finally found a usable solution, it involves code generating code (not elegant and unpredictable sometimes) to get it to be "eval safe", by this I mean that variables like X or Y won't be replace by their values.

The result is a function called cprods that will return a function ready to compute the cartesian product for the limits and the variables passed to it. If a given point is within the specified boundaries, then the result will be true, and false otherwise.

#cas
cprods(variables_, limits_):= begin
  local size_, index_, var_name_, ll_name_, ul_name_;
  local var_list_, cond_, result_, gprogram_, tmp_mark_;
  size_ := min(size(variables_), size(limits_));
  // Since we're defining temp globals we should
  // randomize the names to avoid name collisions
  tmp_mark_ := rand(100000000);
  gprogram_ := 'program';
  var_name_:=(index_)->"variable_" + index_ + "_" + tmp_mark_ + "_";
  ll_name_:=(index_)->"lower_limit_" + index_ + "_" + tmp_mark_ + "_";
  ul_name_:=(index_)->"upper_limit_" + index_ + "_" + tmp_mark_ + "_";
  cond_ := "";
  var_list_ := "{ "
  for index_ from 1 to size_ step 1 do
    (#(var_name_(index_))) := variables_[index_];
    (#(ll_name_(index_))) := limits_[index_,1];
    (#(ul_name_(index_))) := limits_[index_,2];
    if index_ > 1 then
      cond_ := cond_ + " AND "
      var_list_ := var_list_ + ", ";
    end;
    var_list_ := var_list_ + var_name_(index_);
    cond_ := cond_ + ll_name_(index_) + " ≤ " + var_name_(index_) + " ≤ " + ul_name_(index_);
  end;
  var_list_ := var_list_ + " }";
  result_ := expr("gprogram_("+ var_list_ +", nop, '" + cond_ + "')");
  for index_ from 1 to size_ step 1 do
    cas("purge(" + var_name_(index_) + ");");
    cas("purge(" + ll_name_(index_) + ");");
    cas("purge(" + ul_name_(index_) + ");");
  end;
  return result_;
end;
#end

With this function defined we can pass to it our limits and variables, then pass the returned function to the Advanced Graphing app.

par = {f = 1,v = {y,x},l = {{(16-x^2)/8,√(16-x^2)},{0,4}}}
Advanced_Graphing::V1:=cprods({'X','Y'},(l(par))((v(par)) = {'X','Y'}))

Discrete mean for n-dimensional functions

This program will compute the center of gravity or discrete mean given a function describing density (function_) with respect to the variables passed as the list vars_, within the limits defined in limits_, the input format is the same as for iint which also needs to be defined for this to make use of it. This returns a vector representing the center of gravity or discrete mean. The total number for integrals computed by this function varies depending on the size of vars_, and it 's equal to d+d*d where d is equal the size of said list.

#cas
dmean(function_, vars_, limits_):= begin
  local index_, size_, result_, total_;
  result_ := [];
  total_ := iint(function_, vars_, limits_); 
  size_ := min(size(vars_), size(limits_));
  for index_ from 1 to size_ do 
    result_[index_] := 
      iint(function_ * vars_[index_], 
           vars_, limits_)/total_;
  end;
  return result_;
end;
#end

Fourier series

This function will compute the Fourier series for a periodic function expr_ with var_ defined in a_ .. a_ + T_ up to the n_th term. If the optional parameter save_ is set to false then the an_th and bn_th terms won't be calculated for the symbolic value of n_, this can be useful if the expression for these can only be solved using numerical approximations.

#cas
fourier_series(expr_, var_, T_, n_, a_, save_ = true):= begin
  local args_, i_, result_, an_, bn_, saved_b_, saved_a_, ni_;
  args_ := [expr_, var_, T_, nvar_, a_];
  if save_ then
    saved_a_ := fourier_an(op(args_));
    saved_b_ := fourier_bn(op(args_));
    an_ := 'limit(saved_a_, nvar_, ni_)';
    bn_ := 'limit(saved_b_, nvar_, ni_)';
  else
    an_ := 'fourier_an(op(subst(args_, nvar_=ni_)))'
    bn_ := 'fourier_bn(op(subst(args_, nvar_=ni_)))'
  end;
  ni_ := 0;
  result_ := (1/2) * eval(an_);
  for ni_ from 1 to n_ do
    result_ += eval(an_) * cos(2*ni_*π*var_/T_) + eval(bn_) * sin(2*ni_*π*var_/T_);
  end;
  return result_;
end;
#end
fourier_series(x, x, 2, 20, -1)

Misc

Terms of a series to terms of a sum

This program only contains a function that takes a vector and returns a vector of the same size where an nth element is progressively defined as the sum of its value on the nth position at original vector and the value of the nth - 1 element of the returned vector. For example the function call vec_acc([x, y, z]) would yield the expression [x, x+y, x+y+z], given the variables x, y and z are interpreted as symbolic.

#cas
vec_acc(vec):=
begin
  local a, res;
  res := vec;
  for a from 2 to size(vec) do
    res[a] := res[a-1] + res[a];
  end;
  return res;
end;
#end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment