Part 1
If we have this
[> restart; a[5]:=23: a[7]:=41:
then
[> about(a); whattype(a);
a:
nothing known about this object
symbol
but
[> print(a);
table([5 = 23, 7 = 41])
and
[> convert(a,list);
[23, 41]
So Maple does have enough information about variable a and its indexes somewhere. How can we check that information without printing?
For small indexes it's not a problem, but if b[123457891234578912345789]:=789; then how do we check if there is some index i for which b[i] has a defined value and what that index i is (without printing, i. e. not manually)?
Part 2
I'd like to be able to work with such variables inside a function and return such variable.
For example, let's say I want to increase all indexes by 1. If I know which indexes exist then I can do that
[> a[5]:=23: a[7]:=41:
f:=proc(x) local y;
y[6]:=x[5]; y[8]:=x[7]; y;
end proc:
b:=f(a); b[6]; b[8];
b:=y
23
41
but often I don't know what indexes variable a has.
There are several programmatic queries you can make,
restart;
a[5]:=23: a[7]:=41:
# test whether a is assigned
assigned('a');
true
# test whether a is assigned a table
type(a, table);
true
# test whether table a has any indexed values
evalb( nops([indices(a, 'nolist')]) > 0 );
true
assigned('a'[7]);
true
If you wish you can make such queries prior to attempting to access and utilize the indexed reference (ie. to check that it has an assigned value). For example,
if type(a,table) and assigned('a'[7]) then
a[7];
end if;
41
if type(a, table) then
[indices(a, 'nolist')];
end if;
[5, 7]
Related
I'm trying to implement the 'Sport Scheduling Problem' (with a Round-Robin approach to break symmetries). The actual problem is of no importance. I simply want to declare the value at x[1,1] to be the set {1,2} and base the sets in the same column upon the first set. This is modelled as in the code below. The output is included in a screenshot below it. The problem is that the first set is not printed as a set but rather some sort of range while the values at x[2,1] and x[3,1] are indeed printed as sets and x[4,1] again as a range. Why is this? I assume that in the declaration of x that set of 1..n is treated as an integer but if it is not, how to declare it as integers?
EDIT: ONLY the first column of the output is of importance.
int: n = 8;
int: nw = n-1;
int: np = n div 2;
array[1..np, 1..nw] of var set of 1..n: x;
% BEGIN FIX FIRST WEEK $
constraint(
x[1,1] = {1, 2}
);
constraint(
forall(t in 2..np) (x[t,1] = {t+1, n+2-t} )
);
solve satisfy;
output[
"\(x[p,w])" ++ if w == nw then "\n" else "\t" endif | p in 1..np, w in 1..nw
]
Backend solver: Gecode
(Here's a summarize of my comments above.)
The range syntax is simply a shorthand for contiguous values in a set: 1..8 is a shorthand of the set {1,2,3,4,5,6,7,8}, and 5..6 is a shorthand for the set {5,6}.
The reason for this shorthand is probably since it's often - and arguably - easier to read the shorthand version than the full list, especially if it's a long list of integers, e.g. 1..1024. It also save space in the output of solutions.
For the two set versions, e.g. {1,2}, this explicit enumeration might be clearer to read than 1..2, though I tend to prefer the shorthand version in all cases.
I'm using Python3.7.2
The code which makes me confused looks like this:
def foo(cond):
if cond:
z = 1
return z
else:
loc = locals()
x = 1
locals()['y'] = 2
exec("z = x + y")
print(loc)
print(locals())
foo(False)
Here is the result it prints:
{'cond': False, 'loc': {...}, 'x': 1, 'y': 2, 'z': 3}
{'cond': False, 'loc': {...}, 'x': 1, 'y': 2}
The exec function changes the local namespace, but when I execute locals(), variable z disappeared.
However, if I change the code like this:
def foo(cond):
if cond:
return 1
else:
loc = locals()
x = 1
locals()['y'] = 2
exec("z = x + y")
print(loc)
print(locals())
foo(False)
The result will be:
{'cond': False, 'loc': {...}, 'x': 1, 'y': 2, 'z': 3}
{'cond': False, 'loc': {...}, 'x': 1, 'y': 2, 'z': 3}
I'm really confused. :(
In short: the dictionary returned by locals() is only a copy of the true local variables—which are stored in an array, not in a dictionary. You can manipulate the locals() dictionary, add or remove entries at will. Python does not care since that is merely a copy of the local variables it works with. However, each time you call locals(), Python copies the current values of all local variables into the dictionary, replacing anything else you or exec() put in before. So, if z is a proper local variable (as in the first, but not second version of your code), locals() will restore its current value, which happens to be "not set" or "undefined".
Indeed, conceptually Python stores local variables in a dictionary, which can be retrieved through the function locals(). However, internally, it really is two arrays. The names of the locals are an attribute of the code itself and therefore stored in the code object as code.co_varnames. Their values, however, are stored in the frame as fast (which is inaccessible from Python code). You can find more on co_varnames etc. in inspect and dis modules, respectively.
The built-in function locals() actually calls a method fastToLocals() on the current frame object. If we were to write the frame with its fastToLocals method in Python, it might look like this (I am leaving out a lot of details here):
class frame:
def __init__(self, code):
self.__locals_dict = None
self.f_code = code
self.__fast = [0] * len(code.co_varnames)
def fastToLocals(self):
if self.__locals_dict is None:
self.__locals_dict = {}
for (key, value) in zip(self.f_code.co_varnames, self.__fast):
if value is not null: # Remember: it's actually C-code
self.__locals_dict[key] = value
else:
del self.__locals_dict[key] # <- Here's the magic
return self.__locals_dict
def locals():
frame = sys._getframe(1)
frame.fastToLocals()
In plain English: the dictionary you get when calling locals() is cached in the current frame. Calling locals() repeatedly will give you the same dictionary (__locals_dict in the code above). However, each time, you call locals(), the frame will update the entries in this dictionary with the current values that local variables have at that time. As noted here, when a local variable is not set, the entry in the __locals_dict is deleted. And that's what it is all about.
In your first version of the code, the third line says z = 1, which makes z a local variable. In the else branch, however, that local variable z is not set (i.e. would raise a UnboundLocalError) and is therefore removed from the __locals_dict. In the second version of your code, there is no assignment to z, so it is not a local variable and the locals() function does not care about it.
The set of local variables is actually fixed by the compiler. This means that you cannot add or remove local variables at runtime. This is a problem for exec(), as you are clearly using exec() here to define a local variable z. Python's way out is to say that exec() stores z as a local variable in the _locals_dict dictionary, although it cannot put it into the arrays behind this dictionary.
Conclusion: The values of local variables are actually stored in an array, not in the dictionary returned by locals(). When calling locals(), the dictionary is updated with the true current values taken from the dictionary. exec(), on the other hand, can only store its local variables in the dictionary, not in the array. If z is a proper local variable, it will be overwritten by a call to locals() with its current value (which is "does not exist"). If z is not a proper local variable, it will stay in the dictionary untouched.
Python's specifications say that any variable that you assign to inside a function is a local variable. You can change this default through the use of global or nonlocal, of course. But as soon as you write z = ..., z becomes a local variable. If, on the other hand, you only have x = z in your code, the compiler assumes that z is rather a global variable. That's why the line z = 1 makes all the difference: it marks z as a local variable that receives its place in the fast array.
Concerning exec(): in general, there is no way the compiler could really know what code exec() is going to execute (in your case with a string literal it could, but since this is a are rare and uninteresting case, it never tries, anyway). The compiler can therefore not know what local (or global) variables the code in exec() might access, and cannot include that in its calculation of how large the array of local variables should be.
By the way: that local variables are managed in arrays instead of proper dictionaries is the reason why there might be raised an UnboundLocalError instead of an NameError. In case of local variables, the Python interpreter actually recognises the name and knows exactly where its value is to be found (inside the fast array mentioned above). But if that entry is null, it cannot return something meaningful and therefore raises the UnboundLocalError. For global names, however, Python goes really searched for a variable with the given name in the globals and built-in dictionaries. In that case, a variable of the requested name might truly not exist.
Compare your code with the following:
def foo(cond):
if cond:
return 1
else:
loc = locals().copy()
# ——————————————^
x = 1
locals()['y'] = 2
exec("z = x + y")
print(loc)
print(locals())
foo(False)
It produces
{'cond': False}
{'cond': False, 'loc': {'cond': False}, 'x': 1, 'y': 2, 'z': 3}
as you might expect. The reason is that locals() is a reference, not a value.
I have an if statement something like
t(2,5)
P(6,1)
if x:length(t)
t(2,3)>P
P=0
elseif t(2,3)<P
P=1
end
basically what I want to achieve is a loop that runs through t and compares it to p, if the value of t is smaller than the value of P a new matrix should be created and record the value as "1", if the value of t is bigger than the value of P record value as "0", I can't get it to work unfortunately.
If you just want to check if the values in array/matrix t is less than a certain constant value, say P, then better run t<P. That will do the job.
If t and P are both matrices, of equal length, then also you can use t<P. No need for loops or if statements.
I need a container with API like:
addKeyValuePair(containerRef, [key, value])
searchByKey(containerRef, key) #that would return NULL or `value`
How to create such thing in Maple (15)?
You might just want usual indexing into a table. Note that previously unassigned name Y below becomes a table just by virtue of assigning to some indexed entry Y[a].
restart:
Y[a]:=211:
Y[a];
211
Y[b];
Y[b]
assigned(Y[a]);
true
assigned(Y[b]);
false
eval(Y);
table([a = 211])
Having said all that, it's only a small bit of wrapping to get the functionality you've described, where accessing Y[b] returns NULL when Y[b] is not yet assigned, etc.
You can of customize (or remove) the error checking and restriction that key be of type symbol, as Maple allows a table to be indexed more generally.
restart:
addKeyValuePair:=proc(containerRef::{indexed,symbol}, L::list)
if nops(L) <> 2 then
error "expecting list with two entries"; end if;
if not type(L[1], symbol) then
error "expecting list with symbol as first entry"; end if;
containerRef[L[1]]:=L[2];
NULL;
end proc:
searchByKey:=proc(containerRef::{indexed,symbol}, key::name)
if assigned(containerRef[key]) then
containerRef[key];
else
NULL;
end if;
end proc:
addKeyValuePair( Y, [a, 4.5] );
searchByKey( Y, a );
4.5
searchByKey( Y, b );
searchByKey( Q, b );
addKeyValuePair( Y, [a, 211] );
searchByKey( Y, a );
211
addKeyValuePair( Y, [c] );
Error, (in addKeyValuePair) expecting list with two entries
addKeyValuePair( Y, [2.34, 211] );
Error, (in addKeyValuePair) expecting list with symbol as first entry
A table is a mutable data structure. It is of type last_name_eval and in consequence it (effectively) gets passed "by reference" as argument to a procedure call.
So, we are trying to execute the following code. The two if statements are executing, however, the inside if statements are failing to execute (we verified this by not suppressing the output). Is there a reason why? Or are we just not able to reach this state?
Specifications
The input is as follows: v is a vector of int values and c is a integer. c must be less than or equal to one of the values within v
The problem that we are trying to solve with this algorithm is as follows:
Given a cash register, how does one make change such that the fewest coins
possible are returned to the customer?
Ex: Input: v = [1, 10, 25, 50], c = 40. Output O = [5, 1, 1, 0]
We are just looking for not a better solution but more of a reason why that portion of the code is not executing.
function O = changeGreedy(v,c)
O = zeros(size(v,1), size(v,2));
for v_item = 1:size(v,2)
%locate largest term
l_v_item = 1
for temp = 2:size(v,2)
if v(l_v_item) < v(temp)
l_v_item = temp
end
end
%"Items inside if statement are not executing"
if (c > v(l_v_item))
v(l_v_item) = -1 %"Not executing"
else
O(l_v_item) = idivide(c, v(l_v_item)) %"Not executing"
c = mod(c, v(l_v_item)) %"Not executing"
end
end
If c or v are not integers, i.e. class(c) evaluates to double, then I get the following error message
??? Error using ==> idivide>idivide_check at 66
At least one argument must belong to an integer class.
Error in ==> idivide at 42
idivide_check(a,b);
and the program stops executing. Thus, the inside of the second statement never executes. In contrast, if, say, c is an integer, for example of class uint8, everything executes just fine.
Also: what are you actually trying to achieve with this code?
Try to do this operation on your input data:
v = int32([1, 10, 25, 50]), c = int32(40)
and run again, at least some portions of your code will execute. There is an error raised by idivide, which apparently you missed:
??? Error using ==> idivide>idivide_check at 67
At least one argument must belong to an integer class.
Error in ==> idivide at 42
idivide_check(a,b);
Indeed, idivide seems to require that you have actual integer input data (that is, class(c) and class(v) both evaluate to an integer type, such as int32).