1

As a novice in Mathematica I would like to expand an expression without substituting its variables so that

x = 4; y = 4;
Expand[(x^2 + y^2)/x^2]

generates the same output as

x =.; y =.;
Expand[(x^2 + y^2)/x^2]

The only option I found was

x = 4; y = 4;
Expand[(Hold[x]^2 + Hold[y]^2)/Hold[x]^2]

But that is not a feasible solution for more complex expressions. Surely there must be a simpler way to achieve this. Any help would be much appreciated!

userrandrand
  • 5,847
  • 6
  • 33
  • 3
    Why fight against your own definitions? There is an infinite supply of more symbols if you need more. You can also adjust the formatting of symbols using Format, for example Format[xx] = "x" means that xx will henceforth print as x, though it remains different from the symbol x. You can (and should!) localize symbols using Module. – user293787 Oct 26 '22 at 09:12
  • Just for context, I am writing a text containing calculations. To keep things readable I would like to be able to re-use the same symbols, even after defining them – Joost Keuskamp Oct 26 '22 at 10:03
  • 1
    Why is the solution using Hold not feasible? You can always use something like Unevaulated[...] /. {x->Hold[x], y->Hold[y]} to replace all symbols before evaluation, or even Unevaluated[...] /. sym:x|y :> Hold[sym] – Lukas Lang Oct 27 '22 at 12:16
  • Have you seen Module and Block? They are just solving the problem of re-using symbols independently of their values received before. – Alexei Boulbitch Oct 27 '22 at 13:05
  • It seems to me that the title might be too restrictive. It should maybe be something like "symbolic manipulations of predefined variables without numerical substitution" – userrandrand Oct 27 '22 at 19:23

2 Answers2

5

You need only one Hold if you do it like this

x = 4; y = 4;
Block[
   {x, y},
   Hold[ Evaluate @ Expand[(x^2 + y^2)/x^2] ]
] 

enter image description here

However, as pointed out by @user293787 in the comments, you are unnecessarily making it difficult to yourself for no apparent reason.

If you want to clear the definitions of $x$ and $y$ you can use Unset or ClearAll.

I suggest you learn to embrace a different programming style that take advantage of Functional Programming, keeping variable definitions to a minimum. Learn about Scoping Constructs and Transformation Rules like ReplaceAll and keep a clean Kernel.

ClearAll[x, y]

expr = Expand[(x^2 + y^2)/x^2]

1 + y^2/x^2

ReplaceAll[expr, {x -> 4, y -> 4}]

2

rhermans
  • 36,518
  • 4
  • 57
  • 149
3

Contents:

  • Purpose of codes below

  • Method 1: Create a new context

  • Method 2: Turn the variables to strings

  • Method 3: Localize all variables and use Format

Purpose of codes below

Below are some possibilities that try to avoid using tedious code each time one wants to use symbolic computations with predefined variables. That is, the purpose of the codes below is to avoid having to use multiple functions such as Hold, HoldForm (like Hold without the wrapper), Block, Module and most importantly avoiding the tedious task of having to specify which variables need to be hidden from their definitions.

Method 1 : Create a new context.


Advantage: Make multiple symbolic computations in multiple cells while the context is activated.

Risk: Forgetting to leave the context or having to make a keyboard shortcut that makes context opening and context closing cells. Error messages of shadowing are shown each time. If we use Quiet then there is the risk that errors we do not want will not be seen.

Tedious part: One has to make 2 other cells with function calls BeginLocal[](defined below) and EndLocal[](defined below) before writing what we want. Also context errors will appear each time. Finally we have to remember to evaluate EndLocal[] once we are done.


The answer here provides one way to use symbolic calculations with predefined variables. The tedious and maybe dangerous part with that method is that one has to do 3 steps:

  • 1: Evaluate the function BeginLocal[] (defined below) in one cell

  • 2: The code you wanted to use in another cell

  • 3: Evaluate the function EndLocal[] (defined below) in another cell

There is maybe a risk here that the user will forget to use EndLocal[]. One should probably make both the BeginLocal[] and EndLocal[] cells before writing the code for an expression we want to manipulate and then we have to evaluate EndLocal[] at the end. Perhaps this could be made easier with keyboard shortcuts. Search stack exchange for methods to create keyboard shortcuts.

The code from that answer:

Module[{isEx, conlst}, 
BeginLocal[] := Module[{con}, conlst = $ContextPath;
BeginPackage[SymbolName@con <> "`"];];
System`EndLocal[] := 
If[ValueQ@conlst, EndPackage[]; $ContextPath = conlst; 
Clear@conlst];]

Example

x=4;y=4;

First input cell:

BeginLocal[]

Second input cell :

Expand[(x^2 + y^2)/x^2]

Third input cell :

EndLocal[]

Method 2: Turn the variables to strings

Advantage: No need to use two functions in two different cells and no context shadowing errors.

Risk: It seems unlikely for how I use Mathematica but maybe one would defined both the variable x and the string "x" in which case the code below will not work.

Tedious part: we have to use the function hide(defined below) like code //hide each time. If we have many symbolic calculations it might be better to use the BeginLocal[] and EndLocal[] functions from the previous method.

The code below is inspired by the answer here:

ClearAll[hide];
SetAttributes[hide, HoldAll];
hide[code_] := 
ReleaseHold@
ReplaceAll[Hold[code], 
s_Symbol /; Context[s] == "Global`" :> ToString@Unevaluated@s]

x = 4; y = 4; Expand[(x^2 + y^2)/x^2] // hide

Out: $$ \frac{\text{y}^2}{\text{x}^2}+1 $$

However, although the expression looks like what we wanted, x and y are strings as can be checked using FullForm:

x = 4; y = 4; Expand[(x^2 + y^2)/x^2] // hide // FullForm

Out: Plus[1,Times[Power["x",-2],Power["y",2]]]

Method 3: Use Format

Advantage : No issue with the case where one defines both x and the string "x" as "x" is used only for formatting and same advantage as the previous method.

Tedious part: Same as for the previous method

Using Format was mentioned by @user293787 in the comments.

The code below is inspired by the answer (same as for method 2) here:

ClearAll[hide];
SetAttributes[hide, HoldAll];
hide[code_] :=
Module[{vars, modcode},

(association of the form Hold[variable]->{variable to string, localized variable (added dollar sign followed by number)})

vars = Association@ Cases[Hold[code], s_Symbol /; Context[s] == "Global`" :> (Hold@s -> {ToString@Unevaluated@s, Unique@Unevaluated@s}), All];

(* modified input code/expression with localized variables *)

modcode = ReplaceAll[Hold[code], s_Symbol /; Context[s] == "Global`" :> Last@vars@Hold@s];

(Formating the localized variables to look like the original
variables
)

Do[With[{string = First@vars@key}, Format[Last@vars@key] := string], {key, Keys@vars}];

modcode // ReleaseHold

]

Example

x = 4; y = 4; Expand[(x^2 + y^2)/x^2] // hide

Out: $$\frac{\text{y}^2}{\text{x}^2}+1$$

userrandrand
  • 5,847
  • 6
  • 33