Perl 6 reports "Cannot unbox a type object" when typing an array - raku

I suspect this may be a bug in Rakudo, but I just started playing with Perl 6 today, so there's a good chance I'm just making a mistake. In this simple program, declaring a typed array inside a sub appears to make the Perl 6 compiler angry. Removing the type annotation on the array gets rid of the compiler error.
Here's a simple prime number finding program:
#!/usr/bin/env perl6
use v6;
sub primes(int $max) {
my int #vals = ^$max; # forcing a type on vals causes compiler error (bug?)
for 2..floor(sqrt($max)) -> $i {
next if not #vals[$i];
#vals[2*$i, 3*$i ... $max-1] = 0;
}
return ($_ if .Bool for #vals)[1..*];
}
say primes(1000);
On Rakudo Star 2016.07.1 (from the Fedora 24 repos), this program gives the following error:
[sultan#localhost p6test]$ perl6 primes.p6
Cannot unbox a type object
in sub primes at primes.p6 line 8
in block <unit> at primes.p6 line 13
If I remove the type annotation on the vals array, the program works correctly:
...
my #vals = ^$max; # I removed the int type
...
Am I making a mistake in my usage of Perl 6, or is this a bug in Rakudo?

There's a potential error in your code that's caught by type checking
The error message you got draws attention to line 8:
#vals[2*$i, 3*$i ... $max-1] = 0;
This line assigns the list of values on the right of the = to the list of elements on the left.
The first element in the list on the left, #vals[2*$i], gets a zero.
You didn't define any more values on the right so the rest of the elements on the left are assigned a Mu. Mus work nicely as placeholders for elements that do not have a specific type and do not have a specific value. Think of a Mu as being, among other things, like a Null, except that it's type safe.
You get the same scenario with this golfed version:
my #vals;
#vals[0,1] = 0; # assigns 0 to #vals[0], Mu to #vals[1]
As you've seen, everything works fine when you do not specify an explicit type constraint for the elements of the #vals array.
This is because the default type constraint for array elements is Mu. So assigning a Mu to an element is fine.
If you felt it tightened up your code you could explicitly assign zeroes:
#vals[2*$i, 3*$i ... $max-1] = 0 xx Inf;
This generates a (lazy) infinite list of zeroes on the RHS so that zero is assigned to each of the list of elements on the LHS.
With just this change your code will work even if you specify a type constraint for #vals.
If you don't introduce the xx Inf but do specify an element type constraint for #vals that isn't Mu, then your code will fail a type check if you attempt to assign a Mu to an element of #vals.
The type check failure will come in one of two flavors depending on whether you're using object types or native types.
If you specify an object type constraint (eg Int):
my Int #vals;
#vals[0,1] = 0;
then you get an error something like this:
Type check failed in assignment to #vals; expected Int but got Mu (Mu)
If you specify a native type constraint (eg int rather than Int):
my int #vals;
#vals[0,1] = 0;
then the compiler first tries to produce a suitable native value from the object value (this is called "unboxing") before attempting a type check. But there is no suitable native value corresponding to the object value (Mu). So the compiler complains that it can not even unbox the value. Finally, as hinted at at the start, while Mu works great as a type safe Null, that's just one facet of Mu. Another is that it's a "type object". So the error message is Cannot unbox a type object.

Related

Assign a Seq(Seq) into arrays

What is it the correct syntax to assign a Seq(Seq) into multiple typed arrays without assign the Seq to an scalar first? Has the Seq to be flattened somehow? This fails:
class A { has Int $.r }
my A (#ra1, #ra2);
#create two arrays with 5 random numbers below a certain limit
#Fails: Type check failed in assignment to #ra1; expected A but got Seq($((A.new(r => 3), A.n...)
(#ra1, #ra2) =
<10 20>.map( -> $up_limit {
(^5).map({A.new( r => (^$up_limit).pick ) })
});
TL;DR Binding is faster than assignment, so perhaps this is the best practice solution to your problem:
:(#ra1, #ra2) := <10 20>.map(...);
While uglier than the solution in the accepted answer, this is algorithmically faster because binding is O(1) in contrast to assignment's O(N) in the length of the list(s) being bound.
Assigning / copying
Simplifying, your non-working code is:
(#listvar1, #listvar2) = list1, list2;
In Raku infix = means assignment / copying from the right of the = into one or more of the container variables on the left of the =.
If a variable on the left is bound to a Scalar container, then it will assign one of the values on the right. Then the assignment process starts over with the next container variable on the left and the next value on the right.
If a variable on the left is bound to an Array container, then it uses up all remaining values on the right. So your first array variable receives both list1 and list2. This is not what you want.
Simplifying, here's Christoph's answer:
#listvar1, #listvar2 Z= list1, list2;
Putting the = aside for a moment, Z is an infix version of the zip routine. It's like (a physical zip pairing up consecutive arguments on its left and right. When used with an operator it applies that operator to the pair. So you can read the above Z= as:
#listvar1 = list1;
#listvar2 = list2;
Job done?
Assignment into Array containers entails:
Individually copying as many individual items as there are in each list into the containers. (In the code in your example list1 and list2 contain 5 elements each, so there would be 10 copying operations in total.)
Forcing the containers to resize as necessary to accommodate the items.
Doubling up the memory used by the items (the original list elements and the duplicates copied into the Array elements).
Checking that the type of each item matches the element type constraint.
Assignment is in general much slower and more memory intensive than binding...
Binding
:(#listvar1, #listvar2) := list1, list2;
The := operator binds whatever's on its left to the arguments on its right.
If there's a single variable on the left then things are especially simple. After binding, the variable now refers precisely to what's on the right. (This is especially simple and fast -- a quick type check and it's done.)
But that's not so in our case.
Binding also accepts a standalone signature literal on its left. The :(...) in my answer is a standalone Signature literal.
(Signatures are typically attached to a routine without the colon prefix. For example, in sub foo (#var1, #var2) {} the (#var1, #var2) part is a signature attached to the routine foo. But as you can see, one can write a signature separately and let Raku know it's a signature by prefixing a pair of parens with a colon. A key difference is that any variables listed in the signature must have already been declared.)
When there's a signature literal on the left then binding happens according to the same logic as binding arguments in routine calls to a receiving routine's signature.
So the net result is that the variables get the values they'd have inside this sub:
sub foo (#listvar1, #listvar2) { }
foo list1, list2;
which is to say the effect is the same as:
#listvar1 := list1;
#listvar2 := list2;
Again, as with Christoph's answer, job done.
But this way we'll have avoided assignment overhead.
Not entirely sure if it's by design, but what seems to happen is that both of your sequences are getting stored into #ra1, while #ra2 remains empty. This violates the type constraint.
What does work is
#ra1, #ra2 Z= <10 20>.map(...);

Summation iterated over a variable length

I have written an optimization problem in pyomo and need a constraint, which contains a summation that has a variable length:
u_i_t[i, t]*T_min_run - sum (tnewnew in (t-T_min_run+1)..t-1) u_i_t[i,tnewnew] <= sum (tnew in t..(t+T_min_run-1)) u_i_t[i,tnew]
T is my actual timeline and N my machines
usually I iterate over t, but I need to guarantee the machines are turned on for certain amount of time.
def HP_on_rule(model, i, t):
return model.u_i_t[i, t]*T_min_run - sum(model.u_i_t[i, tnewnew] for tnewnew in range((t-T_min_run+1), (t-1))) <= sum(model.u_i_t[i, tnew] for tnew in range(t, (t+T_min_run-1)))
model.HP_on_rule = Constraint(N, rule=HP_on_rule)
I hope you can provide me with the correct formulation in pyomo/python.
The problem is that t is a running variable and I do not know how to implement this in Python. tnew is only a help variable. E.g. t=6 (variable), T_min_run=3 (constant) and u_i_t is binary [00001111100000...] then I get:
1*3 - 1 <= 3
As I said, I do not know how to implement this in my code and the current version is not running.
TypeError: HP_on_rule() missing 1 required positional argument: 't'
It seems like you didn't provide all your arguments to the function rule.
Since t is a parameter of your function, I assume that it corresponds to an element of set T (your timeline).
Then, your last line of your code example should include not only the set N, but also the set T. Try this:
model.HP_on_rule = Constraint(N, T, rule=HP_on_rule)
Please note: Building a Constraint with a "for each" part, you must provide the Pyomo Sets that you want to iterate over at the begining of the call for Constraint construction. As a rule of thumb, your constraint rule function should have 1 more argument than the number of Pyomo Sets specified in the Constraint initilization line.

Passed array with more elements that expected in subroutine

I have a subroutine in a shared library:
SUBROUTINE DLLSUBR(ARR)
IMPLICIT NONE
INTEGER, PARAMETER :: N = 2
REAL ARR(0:N)
arr(0) = 0
arr(1) = 1
arr(2) = 2
END
And let's assume I will call it from executable by:
REAL ARR(0:3)
CALL DLLSUBR(ARR)
Note: The code happily compiles and runs (DLLSUBR is inside a module) without any warning or error in Debug + /check:all option switched on.
Could this lead to memory corruption or some weird behaviour? Where I can find info about passing array with different size in the Fortran specification?
It is actually allowed for explicit shape arrays by the rules of sequence association, if you make the dummy argument element count to be smaller or equal. It is prohibited when the subroutine expects more elements then it gets.
The explicit shape arrays often require the arguments to be passed by a copy. This happens when the compiler cannot prove the array is contiguous (a pointer or an assumed shape array dummy argument). If smaller number of elements was passed, the subroutine could then access some garbage after the copy of the portion of the array.
In your case everything will be OK, because you are passing more to a subroutine expecting less.
Fortran 2008 12.5.2.11.4:
4 An actual argument that represents an element sequence and
corresponds to a dummy argument that is an array is sequence
associated with the dummy argument if the dummy argument is an
explicit-shape or assumed-size array. The rank and shape of the actual
argument need not agree with the rank and shape of the dummy argument,
but the number of elements in the dummy argument shall not exceed the
number of elements in the element sequence of the actual argument. If
the dummy argument is assumed-size, the number of elements in the
dummy argument is exactly the number of elements in the element
sequence.

How to deal with this error?

I'm dealing with very long lists, and large trees.
Sometimes I would find this error:
surgery a;;
Characters 8-9:
surgery a;;
^
Error: This expression has type int t/1044
but an expression was expected of type 'a t/1810
# type 'a t = | Leaf of ('a -> 'a -> int)
| Node of 'a * 'a t * 'a t * ('a -> 'a -> int)
I'm not sure about what type is that kind of error, but I guess it's some kind of an overflow. The type matches correctly but there are large numbers after the backslash that follows the type. In this case 1044 and 1810.
This time I have run some code before surgery a. If I kill the current top-level and start over, surgery a would run.
My questions are:
1. What is this error exactly?
2. When and how does it occur?
3. Why rerunning it from a new top-level would make it work?
4. How should I deal with it?
This is a type error, not a runtime error. It does not "cost" anything and is not in any way related to the size of the structures you have in memory.
It happens if you're not careful in the toplevel, and mix two different types with the same name. Compare:
type t = int;;
let f (x : t) = ();;
type u = bool;;
let g (y : u) = f y;;
^
Error: This expression has type u = bool
but an expression was expected of type t = int
with
type t = int;;
let f (x : t) = ();;
type t = bool;;
let g (y : t) = f y;;
^
Error: This expression has type t/1047 = bool
but an expression was expected of type t/1044 = int
This is the exact same typing error happening in both cases: you mixed different types. But in the second case, both have the same name t. The type-system tries to be helpful and tells you about the unique integers it internally assign to names, to make sure there are really unique throughout the program.
This kind of error cannot happen outside the toplevel (when compiling a program the usual way), as it is not possible to define two types with the same name at the exact same path.
How to fix it: if you redefine a type with a new definition that is not equivalent to the previous one, you must be careful to also redefine the operations on this previous type previously recorded in the toplevel. Indeed, they are still typed as expecting the old type, and using them with the new type will result in such errors.

Parameter 3 is not constant in call of system task $fwrite

I am using Xilinx ISE 10.1 to run some verilog code. In the code I want to write the register values of 3 registers in a file, cipher.txt. The following is the code snippet:
if (clk_count==528) begin
f1 = $fopen("cipher.txt", "w");
$fwrite(f1, "clk: %d", clk_count[11:0]);
$fwrite(f1, "plain: %h", plain[31:0]);
$fwrite(f1, "cipher: %h", cipher[31:0]);
$fclose(f1);
end
At the end of execution, the contents of cipher.txt is found as:
clk: %dplain: %hcipher: %h
There is no other error encountered, but a warning comes up corresponding to the 3 fwrite's:
Parameter 3 is not constant in call of system task $fwrite.
Parameter 3 is not constant in call of system task $fwrite.
Parameter 3 is not constant in call of system task $fwrite.
The values of the registers clk_count and cipher change on every clock cycle (value of register plain remains constant throughout), and the values are written to cipher.txt when clk_count equals 528 (indicated by the if statement)
Can anybody provide some insight and/or help me get past this hurdle?
Thanks.
It appears that ISE expects the arguments to $fwrite to be constant. The warnings are referring to clk_count[11:0], plain[31:0], and cipher[31:0], which are not constant. By definition they are changing each cycle so they are not known at compile time. This also explains why they are not printing and you are seeing %d and %h in the output.
There is nothing to my knowledge in the Verilog spec that requires the arguments to $fwrite be constant. The same code works as expected with Cadence Incisive. My guess is that it's a limitation of ISE, so you may want to check with Xilinx.
Possible work-arounds:
1) Use $swrite to create a string with the proper formatting. Then write the string to the file.
2) Try using an intermediate variable in the calls to $fwrite. Maybe the part-selects are throwing it off. e.g.
integer foo;
foo = clk_count[11:0];
$fwrite(... , foo , ...);
Either of those might work, or not.
Out of curiosity, if you remove the part-selects, and try to print clk_count without the [11:0] , do you get the same warnings?