Joe Riel

9660 Reputation

23 Badges

20 years, 3 days

MaplePrimes Activity


These are answers submitted by Joe Riel

What mode are you in, 1D or 2D? In 2D mode, typing the underscore causes the following text to be the underscore. Use the right arrow key to stop entering subscripted text. This actually generates indexed variables, which are displayed as subscripts. This is equivalent to using square brackets, e.g. x[1], in 1D mode.
You have to use < to enter a less-than symbol. Here is a method that should do the job:
temp := [[a = 3, b = 23, c = 34, d = 1], 
         [a = 3, b = -3, c = 3, d = 2], 
         [a = 3, b = 32, c = 4, d = -5], 
         [a = 2, b = -3, c = -3, d = -4]]: 
select(L -> eval(b > 0 and d > 0, L), temp); 
                       [[a = 3, b = 23, c = 34, d = 1]]
I believe the usual way is to truncate a continued fraction expansion. For example,
with(numtheory):
cfrac(77/45,'quotients);
                          [1, 1, 2, 2, 6]
cfrac([%[1..-2]);
                            12/7
which is a much better approximation (0.2%) than 9/5 (5%).
My previous response has disappeared; possibly I hit preview insted of post. You want to create the mathml format `#mover(msub(mi("V"),mi("x")),mo("→"))` Typing that directly into the input gives what you want. Alas, it doesn't appear to be possible to do this with the palettes. Following your first recipe, than selecting the entire object and right clicking to do Convert To --> Inert Form creates the mathml object `#mscripts(mi("V"),mi("x"),none(),none(),mo("→"),none(),none())` which does not display the right arrow, despite it being in the mathml. That appears to be a gui bug.
In Maple, relations are non-associative; you cannot do, for example,
 a < b < c
Instead you must write this as
 a < b and b < c
Apparently (though I haven't tested it) the 2D mode was translating the former to the latter. Here's another approach to finding the value in a list that is nearest a given value. If your list L is already sorted, then you can omit the call to sort.
nearest := proc( L::list, v )
local lst,pos;
    lst := sort(L);
    pos := ListTools:-BinaryPlace(lst, v);
    if pos = 0 then lst[1]
    elif pos = nops(lst) then lst[-1]
    elif v-lst[pos] < lst[pos+1] - v then
        lst[pos]
    else
        lst[pos+1]
    end if;
end proc:
Since you also need the index, you should return that, too.
There are a few things going on. First, you must have typed these in wrong; as given they are expressions, not procedures. Presumably that was a typo in transferring from Maple to MaplePrimes. What you meant was
f1 := x -> piecewise( is(floor(x)::odd), 1, 0 ):
f2 := x -> piecewise( floor(x)::odd, 1, 0 ):
The reason f2 fails is a consequence of the way that the double-colon operator works. It does not automatically evaluate to truefalse. If used in a context where a boolean expression is implied, say in the conditional of an if statement, or with a boolean operator, then it is evaluated. Otherwise it just evaluates to itself. Hmm. But that doesn't explain why a single pulse is generated. Some more reflection is required. However, there are a few ways to work around this. One is to use the evalb command to force the double-colon to be evaluated to true or false:
f3 := x -> piecewise(evalb(floor(x)::odd), 1, 0):
Another is to use type
f4 := x -> piecewise(type(floor(x),odd), 1, 0):
You cann also use an `if` function
f5 := x -> `if`(floor(x)::odd, 1, 0):
I'm missing something. %dm is just a name; it is not related to your procedure dm. I don't see how that makes it inert. Or is the GUI doing something funny with %dm?
Another possibility, though probably less useful than Robert's suggestion, is to use alias.
alias('dm'(rho)=dm(rho), 'dm'(tau)=dm(tau)):
dm(rho) + dm(tau);
                                    dm(rho) + dm(tau)
factor(%);
                             v[c] (d_[c](rho) + d_[c](tau))
Alias works better if the term is a function.
It is good practice to use the returnonly option to ListDirectory. Hence,
files := FileTools:-ListDirectory(path, 'returnonly' = "*.m"):
I prefer using sprint rather than cat, but that is a matter of taste:
for f in files do
   read sprintf("%s/%s", path, f);
end do:
Note that you can also use a forward slash rather than an escaped (doubled) backslash; Windows generally interprets it properly (I suspect one could embed forward slashes in the name of a file and cause problems, but...).
I realized, upon rereading the original post, that we answered the wrong question. He doesn't want to use next to exit more than one loop, rather he wants to use it to increment the counter more than its usual amount. That can be done directly:
for i to 10 do print(i); if i=5 then i:=i+1; next end if end do;
                                                       1
                                                       2
                                                       3
                                                       4
                                                       5
                                                       7
                                                       8
                                                       9
                                                      10
I don't know that I'd recommend that technique, it is potentially troublesome. Nicer might be to use your own loop counter:
cnt := 0;
while cnt < 10 do
   cnt := cnt+1;
   if cnt = 5 then cnt := cnt+1; next end if;
end do;
One can do fun stuff like
timelimit(0.001, proc() local i; for i to 2 do i := i/2; lprint(i) end do end());
1/2
3/4
7/8
15/16
31/32
63/64
127/128
255/256
...
I've occasionally wondered what is the "best" way to do this. Off-hand I can think of four techniques: use flags, use try/catch, use return in a local proc, and use the undocumented goto command. Here is an outline of each; following is comparison of their relative speed. Methods
useflags := proc()
local finished;
    do
        do
            finished := true;
            if finished then break end if
        end do;
        if finished then break end if
    end do
end proc:

usetry := proc()
    try
        do
            do
                error
            end do;
        end do;
    catch:
    end try
end proc:

useproc := proc()
    proc()
        do
            do
                return
            end do
        end do
    end proc()
end proc:

usegoto := proc()
    do
        do
            goto(999);
        end do
    end do;
    999:
end proc:
Comparison executed 106 times:
useflags  3.630
usetry    3.270
useproc   3.089
usegoto   2.790
The order is about what I expected (intuitively, it wasn't clear which of the try or proc methods would be better). Note that using flags will get worse with more nesting levels and actual loop evaluation.
whattype should never be used in a procedure. Use either type or ::. For example,
proc(s::set)
local a;
   for a in s do
      if a::integer then
          return a;
      end if;
   end do;
   NULL;
end proc:
That being said, a nicer way, and one that doesn't depend on the sorting of the set, is
proc(s::set)
   sort(convert(select(type, s, integer), 'list'))[1];
end proc;
Another possibility is
proc(s::set)
   min(select(type, s, integer)[]);
end proc
however, that will return -infinity, rather than NULL, if the set contains no integers. I haven't actually tested these, just wrote them up, so...
Neither approach is particularly, or even approximately, robust. As a minimum, you would want to restrict the indeterminates returned by indets to names, otherwise it will fail with, say, sin(x). Slightly better would be to also eliminate constants, so that, for example, Pi doesn't get returned. I'd also check for a single indeterminate. Hence something like
test := proc(h)
local vars;
   vars := indets(h,'And(name,Not(constant))');
   if nops(vars) > 1 then
      error "too many indeterminates";
   elif vars = {} then
      error "no indeterminates";
   end if;
   eval(h, op(vars)=1.1)
end proc:
If the indeterminate name is already known, which I suspect is the case, then unapply is the way to go.
More generally, use foldl:
n := 4:                           
f := add(k[i]*x[i],i=1..n);
                    f := k[1] x[1] + k[2] x[2] + k[3] x[3] + k[4] x[4]
foldl(int,f,seq(x[i]=0..1,i=1..n));
                    1/2 k[1] + 1/2 k[2] + 1/2 k[3] + 1/2 k[4]

So how'd you do it? Here's one approach. See Cartesian Product of Lists for a comparison of ways to compute the cartesian product of lists. The following CartProdSeq was taken from there.
CartProdSeq := proc(L::seq(list))
local Seq,i,j;
option `Copyright (C) 2007, Joseph Riel. All rights reserved.`;
    eval([subs(Seq=seq, foldl(Seq
                              , [cat(i,1..nargs)]
                              , seq(cat(i,j)=L[j],j=nargs..1,-1)
                             ))]);
end proc:
P := combinat[permute]([0,0,1,1]):
map(Matrix,CartProdSeq(P,P));
 [0    0    1    1]  [0    0    1    1]        [1    1    0    0] 
[[                ], [                ], ...,  [                ]]
 [0    0    1    1]  [0    1    0    1]        [1    1    0    0] 
First 102 103 104 105 106 107 108 Last Page 104 of 114