Transform expression so that all if/then/else are on top level - maxima

I have series of simple equations, which has one input variable x and handful of helper variables, and the result should be an expression in terms of x. Those equations have if/then/else in them. How can I force the final result to only have if/then/else at top level, and not in subexpressions? Ideally I want to receive a result that resembles jagged linear plot equation in the form of if x < step1 then m1 * x + k1 else if x < step2 then m2 * x + k2 else ... where step, m and k would be numeric constants. To give an example, I have
eq1: var1 = if x > 1678 then 400 - 0.18*(x - 642) else 460 - 0.26*(x-730);
eq2: var2 = subst([eq1], if x <= 7520.5 then (x - var1)*0.2 else 7520.5*0.2+(x - 7520.5)*-0.32);
eq3: x - var2;
res: subst([eq1, eq2], eq3);
expand(res);
which currently evaluates to
x-(if x<=7520.5 then 0.2*x-0.2*(if x>1678 then 515.56-0.18*x else 649.8-0.26*x) else 3910.66-0.32*x)

Great question, unfortunately, I don't see an easy way to do that. Here is a sketch of some ideas; I'll try to come back in the next day or two to fill in the details.
First of all, I thought about replacing if/then/else with unit_step, charfun, or charfun2. However, it looks like simplifications for arithmetic on those expressions (e.g. product of unit_step) isn't implemented, so working with any of those wouldn't be any simpler. But if someone else can see how to do it, please, by all means, show us.
The outline of a way that I see to do this is (1) define rules for arithmetic on if/then/else, and (2) define rules for flattening nested if/then/else. I would use defrule to define the rules, although tellsimpafter is also a possibility.
EDIT: I've put together some code to handle (1) and (2) above. See robert-dodier/simplify_conditionals at: https://github.com/maxima-project-on-github/maxima-packages
Here's the result I get for the problem you mentioned.
(%i2) load ("simplify_conditionals.mac");
(%o2) simplify_conditionals.mac
First assign e the expression you showed.
(%i3) e: x-(if x<=7520.5 then 0.2*x-0.2*(if x>1678 then 515.56-0.18*x else 649.8-0.26*x) else 3910.66-0.32*x);
(%o3) x - (if x <= 7520.5 then 0.2 x
- 0.2 (if x > 1678 then 515.56 - 0.18 x else 649.8 - 0.26 x)
else 3910.66 - 0.32 x)
Carry out + and * arithmetic. (- and / are also covered since those are defined in terms of + and * in Maxima.)
(%i4) arithmetic_with_conditionals (e);
(%o4) if x <= 7520.5 then (if x > 1678
then 0.8 x + 0.2 (515.56 - 0.18 x)
else 0.8 x + 0.2 (649.8 - 0.26 x)) else 1.32 x - 3910.66
Call expand to distribute * over + (this is aside from the conditional stuff).
(%i5) e1: expand (%);
(%o5) if x <= 7520.5 then (if x > 1678 then 0.764 x + 103.112
else 0.748 x + 129.96) else 1.32 x - 3910.66
Flatten nested conditionals.
(%i6) e2: flatten_conditionals (e1);
(%o6) if (x <= 7520.5) and (x > 1678) then 0.764 x + 103.112
elseif x <= 7520.5 then 0.748 x + 129.96 else 1.32 x - 3910.66
Okay, that's it. At this point you could verify the result by, e.g., plotting both e and e2 and verifying they're the same, or evaluating e2 - e for values of x and verifying the result is zero or nearly so (since floating point arithmetic can yield very small, nonzero results).
I made some effort to verify the implementation; see rtest_simplify_conditionals.mac. But the tests aren't exhaustive. Also, I didn't try to handle other operations, e.g. exponents or arbitrary functions. All the same, I hope the package is useful to you in some way.

Related

How to declare/use Arrays and Quantifiers in Z3Py?

I'm new to Z3py and I found an exercise where it would ask to check if some verification conditions were true. Up to this moment, the exercises I've done were basically to transform simple propositional formulas into z3py clauses, something like:
Propositional Formula would be:
(n>=4) -> (x = y +2)
Which would become in Z3Py:
n, x, y = Ints('n x y')
s.add(Implies(n>=5, x == y+3))
The conditions I'm presented now, introduce Arrays and Quantifiers and after spending hours trying to figure it out on the documentation around, I'm still not able to get it properly done.
For example, how would I do the same process above but with the following conditions:
n ≥ 1 ∧ i = 1 ∧ m = A[0]
i <= n ∧ ∀j. 0 ≤ j < i → m ≥ A[j]
A little snippet of what I think that is correctly done:
i, n = Ints('i n')
s.add(And(n>=1, i == 1, ???)
s.add(And(i<=n,Implies(???))
How should I replace the ??? so that the conditions would be correctly transformed into Z3Py?
Solution:
- The constraint
n ≥ 1 ∧ i = 1 ∧ m = A[0]
would become in Z3Py:
A = Array('A', IntSort(), IntSort()) //Array declaration
i, n, m, j = Ints('i n m j') //Ints declaration for both constraints
And(n>=1, i==1, m==A[0])
- The constraint
i <= n ∧ ∀j. 0 ≤ j < i → m ≥ A[j]
would become:
And(i<=n,ForAll(j,Implies(And(j>=0,j<i),m>=A[j])))
Your questions is quite ambiguous. Note that you've the constraints:
n ≥ 1 ∧ i = 1
and then
i <= n
but that consequent is already implied by the first, and hence is redundant. Meaning, if you add them both to the solver like you did with your s.add lines, then it won't really mean much of anything at all.
I'm guessing these two lines actually arise in different "subparts" of the problem, i.e., they aren't used together for the same verification goal. And, making an educated guess, you're trying to say something about the maximum element of an array; where i is some sort of a loop-counter. The first line is what happens before the loop starts, and the second is the invariant the loop-body ensures. If this is the case, you should be explicit about that.
Assuming this is the case, then these sorts of problems are usually modeled on the "body" of that loop, i.e., you need to show us exactly what sort of a "program" you're dealing with. That is, these constraints will only make sense in the presence of some sort of a transformation of your program variables.

Simplification of rational expressions

I'm struggling with getting maxima to simplify expressions in the way that I want them.
rhs(solve(a*x-3=b*y,x)[1]);
returns
(b*y+3)/3
However, I'm wanting to display the result to students and so I want the output to be
(b*y/3) + 1
Is there some simplification that I can do to a rational expression in this form to get the output I want?
You can undo the effect of ratsimp in this case by dividing each term in the numerator by the denominator. Here is a simple-minded implementation:
(%i1) unratsimp (e) :=
block ([foo, bar],
[foo, bar]: [num(e), denom(e)],
map (lambda ([foo1], foo1/bar), expand (foo))) $
(%i2) 1 + a/b + c*d/3 - %pi*x/y;
%pi x c d a
(%o2) (- -----) + --- + - + 1
y 3 b
(%i3) ratsimp(%);
(b c d + 3 b + 3 a) y - 3 %pi b x
(%o3) ---------------------------------
3 b y
(%i4) unratsimp(%);
%pi x c d a
(%o4) (- -----) + --- + - + 1
y 3 b
(%i5) unratsimp((b*y + 3)/3);
b y
(%o5) --- + 1
3
I don't know how general that is; it's just the first thing I tried, but maybe it's enough for your purpose. I don't know a built-in function for this.
The results %o4 and %o5 are maybe not exactly as a human would write them. Convincing Maxima to display the terms in + and * expressions in a different way is not straightforward -- Maxima has strong ideas about how to order terms in an expression which are assumed throughout the code. But I think that others have asked questions, which might have answers, about displaying expressions -- you might search Stackoverflow if you are are interested.
The command you can use here is multthru:
(%i1) e1:(b*y+3)/3;
(%o1) (b*y+3)/3
(%i2) multthru(e1);
(%o2) (b*y)/3+1
In this case also the following will work
(%i3) distrib(e1);
(%o3) (b*y)/3+1
(%i4) expand(e1);
(%o4) (b*y)/3+1

How to output equation without evaluation, but with variables replaced to their values?

I need to make tons of simple computations and present each step in my report with predefined manner:
(for ex i got B=2, C=3):
A=B+12-6/C^2; A=2+12-6/3^2=13.333;
I can get 1st block and answer like this:
B:2$ C:3$
A:'(B+12-6/C^2)$
print("A=",A,"; ","A= ??? =",ev(A, numer) );
and get:
6
A= (- --) + B + 12 ; A= ??? = 13.33333333333333
2
C
What i need instead of '???' to get desired output?
Maxima distinguishes two parts of figuring out a result: evaluation and simplification. Evaluation = substituting one thing (the value) for another thing (a variable or a function). Simplification = applying mathematical identities to get a "simpler", equivalent result.
In your problem, it appears you want to postpone simplification. You can say simp: false to do that. Here's one possible approach. I'll disable simplification, substitute values into the expression, print the substituted expression, and then re-enable simplification to get the final result.
(%i2) expr: A=B+12-6/C^2;
6
(%o2) A = (- --) + B + 12
2
C
(%i3) simp: false $
(%i4) subst ([B = 2, C = 3], expr);
- 2
(%o4) A = 12 + 2 + (- 6) 3
(%i5) simp: true $
(%i6) %o4;
40
(%o6) A = --
3
Note that many operations in Maxima happen by simplification (e.g. adding numbers together), so in general, Maxima will act noticeably different when simp is false. But in this case that's what you want.
EDIT: OP points out that the result after substitution is displayed in a somewhat different from. The reason for this has to do with some obscure implementation details of Maxima. Be that as it may, it's possible to work around that behavior by using the Lisp substitution function SUBST (referenced in Maxima as ?subst) instead of Maxima subst. SUBST is a little different than Maxima subst; the syntax is ?subst(new_thing, old_thing, some_expression). After substituting via SUBST, it's necessary to resimplify explicitly; one way to do that is to say expand(..., 0, 0) (which doesn't expand anything, the only effect is to resimplify).
(%i2) expr: A=B+12-6/C^2;
6
(%o2) A = (- --) + B + 12
2
C
(%i3) simp: false $
(%i4) ?subst (3, C, ?subst (2, B, expr));
6
(%o4) A = (- --) + 2 + 12
2
3
(%i5) simp: true $
(%i6) expand (%o4, 0, 0);
40
(%o6) A = --
3
Since SUBST is has a different effect on the internal representation, it is possible you could create an invalid expression, for some choices of new_thing, old_thing, and some_expression. I won't try to sort that out here.

Derivatives using indexed variables

As an example I want to try to find the partial derivatives of
f(x) = \sum_{i=1}^n x_i^2
in Maxima. (The expected output would be \frac{\partial f}{\partial x_k} = 2x_k) I have tried following, but it seems the indexed variables are not handled as I expected, can anyone explain what I am doing wrong?
The same command works if you replace n and k with actual numbers, but not in this form:
f(x) := 1/2 * sum( x[i]^2, i, 1, n);
print(diff(f(x),x[k]));
Try it online!
Maxima can't handle derivative with respect to a indexed variable by default. I wrote a couple of small packages to handle these problems. Perhaps this is useful to you.
See: https://pastebin.com/MmYJRqCq (sum_kron_delta, summation of Kronecker delta)
and: https://pastebin.com/UGCPgvAn (diff_sum, derivative of summation wrt indexed variable)
Here's an example applied to your problem. I'll assume you have downloaded the code above to your computer.
(%i1) load ("sum_kron_delta.mac");
(%o1) sum_kron_delta.mac
(%i2) load ("diff_sum.mac");
(%o2) diff_sum.mac
(%i3) 'diff ('sum (x[i]^2, i, 1, n), x[j]);
n
====
\
(%o3) 2 > x kron_delta(i, j)
/ i
====
i = 1
Note that you have to write 'diff('sum(... that is, with the quote mark ' to indicate that diff and sum are nouns (formal expressions) instead of verbs (functions which are called). This is necessary in the implementation of diff_sum and sum_kron_delta because they work with simplification rules. (It's a long story, which I can explain if there's interest.)
I see we got the kron_delta summation, but we need to cause the simplification rules to be applied. We could also write expand(%, 0, 0) here instead of ''%.
(%i4) ''%;
(%o4) 2 (if (1 <= j) and (j <= n) and %elementp(j, integers) then x else 0)
j
At this point we have the final result, which we can simplify further with additional data.
(%i5) assume (j >= 1, j <= n);
(%o5) [j >= 1, n >= j]
(%i6) ''%o4;
(%o6) 2 (if %elementp(j, integers) then x else 0)
j
(%i7) declare (j, integer);
(%o7) done
(%i8) ''%o6;
(%o8) 2 x
j
If this seems fruitful to you, I'll be happy to go into details.

Kernel Addition and one Surprisingly facts?

if k1 and k2 be a kernel in space R^n*R^n we know k(x,z)=ak1(x,z) + bk2(x,z) (kernel addition) is still a kernel (valid kernel) if a,b >= 0 (a,b is real numbers, scalar) . That this is valid can be seen from the fact that the results of the kernel function can be interpreted as inner products in feature space. Adding the inner products together amounts to adding both feature spaces together. but today i'm so surprised when I read my notes. my TA says k(x,z)=ak1(x,z) + bk2(x,z) (kernel addition) is still a kernel if a<0,b>0 or a>0,b<0 !!!
is it possible to still there is a valid kernel with a<0,b>0 and a>0,b<0? any expert could
help me ?
A kernel should be non-negative for all equal inputs. Let's denote an arbitrary kernel (RBF, for example) as K.
Let's consider K1 = K2 = K.
Define K3 = a K1 + b K2. Let a = -2, b = 1. Then K3(x, x) = -K(x, x), which fails to satisfy kernel's definition.
Now, the example above show that statement of your TA is not true in general, for any K1, K2, a and b. There are, obviously, some combinations of these that will result in a proper kernel.
I suppose, the necessary condition for it would be something like λmin(a K1) + λmin(b K2) >= 0 where λmin means the smallest eigenvalue of an operator. λmin(c K) is equal to c λmin(K) for non-negative c, and c λmax(K) for a negative one. Consider a=2, b=-1 with the same kernels as above as an example.
In case of both a < 0 and b < 0, though, no valid kernel can be forged. This is easy to see: if K3(x, x) > 0, then, K3(x, x) = a K1(x, x) + b K2(x, x) = -|a| K1(x, x) - |b| K2(x, x) > 0 since a and b are negative. This leads to |a| K1(x, x) + |b| K2(x, x) < 0 which can't be true since K1 and K2 are valid kernels.

Resources