I'm currently trying to create a Modelica-Code, that searchs through an Array full of strings, compares them to strings in a different Array and safes the location where it found it and the location of the initial Matrix.
My Code as an example can be seen here:
parameter String Matrix[3,3]={{"Pumpe1","Widerstand1","Ventil1"},{"Zweig","Widerstand2","Ventil2"},{"Druckrand","Widerstand3","Ventil3"}};
parameter String Ueberschrift[1,5]={{"Ventil1","Pumpe1","Druckrand","Ventil3","Ventil2"}};
Integer Stringvergleich;
Integer Ortsvektor[9,3];
Integer Laufvariable;
algorithm
Laufvariable:=0;
for i in 1:3 loop
for l in 1:3 loop
Laufvariable:=Laufvariable + 1;
for m in 1:5 loop
Stringvergleich:=Modelica.Utilities.Strings.find(Ueberschrift[1,m],Matrix[i,l]);
if not Stringvergleich==0 then
Ortsvektor[1,Laufvariable]:=i;
Ortsvektor[2,Laufvariable]:=l;
Ortsvektor[3,Laufvariable]:=m;
end if;
end for;
end for;
end for;
Unfortunately this code seems to be wrong, but I can't figure out what the Problem is. Dymola sends the following Error message:
Index out of bounds
Failed condition: (j>=1)&&(j<=dim)
Error: Integrator failed to start model.
Related
I have a record type(REC) which contains an element of type VECTOR which is an unconstrained 2d array of STD_LOGIC:
package TEST is
type VECTOR is array (NATURAL range <>, NATURAL range <>) of STD_LOGIC;
type REC is record
data : VECTOR;
end record REC;
function con(
a : REC;
b : REC)
return REC;
end package TEST;
When declaring the body of the con function I want to specify the size of the REC.data array like so:
package body TEST is
function con(
a : REC;
b : REC)
return REC is variable r : REC(
data(a.data'length(1) + b.data'length(1) - 1 downto 0, a.data'length(2) - 1 downto 0));
begin
-- . . . do things
end function con;
end package body TEST;
but in the line where I attempt to set the size of data it Vivado throws the following error:
Sliced name is allowed only on single-dimensional arrays
Does this mean I cannot have an unconstrained 2d arraign in a record or is there a different method for defining the size of it in the con function ?
---- EDIT ----
Since I now understand that it is not possible to use 2d arrays in this context what method should I use to create a function which:
Takes two 2d arrays (or arrays of arrays) of size [x][y] and [z][y] as inputs
Outputs an array of size [x+z][y]
With both input arrays being unconstrained and the output array being constrained to size [x+z][y]
And all arrays (input and return) be a record type
user1155120 I don't think I fully understand what you are trying to say. Are you saying my code is not
a minimal reproducible example, because except for me forgetting to include the STD_LOGIC library
the code reproduces the problem when I paste it into Vivado, and it is about as minimal as I can get it.
Or are you saying that the code you linked as this works works for you, because at least in my
Vivado it still throws the same error ? – Mercury 4 hours ago
The original comment was meant for Tricky. There's a missing return statement in the function con which would prevent use in an example.
It isn't clear if record constraints (a -2008 feature) are supported in Vivado Simulator. In Vivado Synthesis Guide UG901 2020.1 we see all sorts of wonderful uses of record types from everything to inferring ram to record elements of record types. Xilinx has been busy.
It'd seems odd if unconstrained elements in record type declarations were supported but not record constraints (they're pretty much a package deal, pun aside). Note the comment called it a -2008 feature.
A record constraint is limited to supply the constraint of an element or subelement that is of an unconstrained type (typically arrays). VHDL has always been capable of supplying multi-dimensional array constraints. The language of the standard is particular based on the flexibility of the syntax.
This code is VHDL -2008 compliant and provides your record constraint:
library ieee; -- ADDED for MCVe
use ieee.std_logic_1164.all; -- ADDED
package TEST is
type VECTOR is array (NATURAL range <>, NATURAL range <>) of STD_LOGIC;
type REC is record
data: VECTOR;
end record REC;
function con (a: REC; b: REC) return REC;
end package TEST;
package body TEST is
function con (a: REC; b: REC) return REC is
variable r:
REC ( -- record constraint:
data (
natural range a.data'length(1) + b.data'length(1) - 1 downto 0,
natural range a.data'length(2) - 1 downto 0
)
);
begin
-- . . . do things
return r; -- ADDED required return statement
end function con;
end package body TEST;
You'll note the changes to the record constraint from yours is the addition of natural range before each range of the element data constraint.
From IEEE Std 1076-2008 5.3.3 Record types:
record_constraint ::=
( record_element_constraint { , record_element_constraint } )
record_element_constraint ::= record_element_simple_name element_constraint
From 6.3 Subtype declarations:
element_constraint ::=
array_constraint
| record_constraint
Here the element data is an array so an array_constraint is appropriate.
From 5.3.2 Array types, 5.3.2.1:
array_constraint ::=
index_constraint [ array_element_constraint ]
| ( open ) [ array_element_constraint ]
Because element data array elements are scalar (enumeration type STD_LOGIC) we follow index_constraint.
index_constraint ::= ( discrete_range { , discrete_range } )
discrete_range ::= discrete_subtype_indication | range
The code shown above uses a discrete subtype indication for the index ranges of the element data dimensions and successfully analyzes (compiles).
From 5.2.2 Scalar types, 5.2.2.1:
range ::=
range_attribute_name
| simple_expression direction simple_expression
direction ::= to | downto
The constraint in the question uses a range with simple expressions and direction.
So why did it produce the error message about multi-dimensional slices?
In 9. Expressions, 9.1 the BNF, simple_expression -> term -> factor -> primary -> name.
In 8. Names, 8.1 name -> slice_name, only multi-dimensional slices are not allowed semantically in 8.5 Slice names who's BNF tells us it's syntactically valid:
slice_name ::= prefix ( discrete_range )
The prefix of a slice shall be appropriate for a one-dimensional array object. The base type of this array type is the type of the slice.
and semantically the prefix data is not appropriate for a one-dimensional array object.
These comments provide bit more context for the problem although it isn't clear which version the record constraint you used in the reported eventual success:
#Mercury when you add a (VHDL) file to Vivado, it's by default set to use VHDL 93, but not 2008. Go
to the property Window and change the file type from VHDL to VHDL 2008. I'm not sure why it
prints the wrong error message in your case. (Vivado likes to confuse users with wrong error messages
...). Anyhow, it should have reported your feature is only supported in 2008 mode. – Paebbels 3 hours
ago
#Paebbels Thank you, that fixed the problem, maybe add it as a sub note to your response so I can
mark it as accepted answer. You just saved me hours of frustration. And I'm already getting familiar with
Vivado's shenanigans, my Favorit one of which is "ERROR close to ..." which has to be one of the most
useless error messages I have experience in a long time :) – Mercury 3 hours ago
As far as detecting -2008 source, there are no -1993 syntax errors and no -2008 new reserved word, delimiters, separators or graphics characters in either the primary unit or the secondary.
That leaves you at the mercy of semantic analysis which failed. You could also note the unconstrained record element wasn't reported during analysis of the package declaration. It occurred during evaluation of the variable r. All declared objects are required to be constrained. VHDL doesn't have a recital of all features, semantics can be restrictive as well. It's legal in places to have unconstrained elements and objects.
Associating semantics rules found in the text of the standard with an textual element of the particular declaration or statement can be tough and the squeaky wheel gets the lubricant. Record constraints are relatively new to VHDL implementations.
The problem appears to have been one of tool familiarity.
This is the definition of row and column merges from PoC's vectors package, see lines starting at 359:
function slm_merge_rows(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
constant ROWS : positive := slm1'length(1) + slm2'length(1);
constant COLUMNS : positive := slm1'length(2);
variable slm : T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
begin
for i in slm1'range(1) loop
for j in slm1'low(2) to slm1'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, j) := slm1(i, j);
end loop;
end loop;
for i in slm2'range(1) loop
for j in slm2'low(2) to slm2'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(slm1'length(1) + i, j) := slm2(i, j);
end loop;
end loop;
return slm;
end function;
function slm_merge_cols(slm1 : T_SLM; slm2 : T_SLM) return T_SLM is
constant ROWS : positive := slm1'length(1);
constant COLUMNS : positive := slm1'length(2) + slm2'length(2);
variable slm : T_SLM(ROWS - 1 downto 0, COLUMNS - 1 downto 0);
begin
for i in slm1'range(1) loop
for j in slm1'low(2) to slm1'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, j) := slm1(i, j);
end loop;
for j in slm2'low(2) to slm2'high(2) loop -- WORKAROUND: Xilinx iSIM work-around, because 'range(2) evaluates to 'range(1); see work-around notes at T_SLM type declaration
slm(i, slm1'length(2) + j) := slm2(i, j);
end loop;
end loop;
return slm;
end function;
The definition of T_SLM is:
type T_SLM is array(natural range <>, natural range <>) of std_logic;
Currently, I see no problem in nesting this code in another layer like your unconstrained record.
Edit:
Thie code above requires VHDL 2008 to be enabled in Vivado.
When VHDL files are added to Vivado, it's by default set to use VHDL 93, but not 2008. Go to the property Window and change the file type from VHDL to VHDL 2008``.
The printed error message is misleading and points to a false feature being used. The correct message should be it's a VHDL-2008 feature, please enable it.
I am currently doing the Ada tutorial from learn.adacore.com, and I am now at the second example: reading and outputting an integer. Since copy-pasting is for people who don't want to learn the syntax, I manually typed out most of the code (Some of it was generated by gnat-gps, but I'm now using vim).
I compiled and ran the program, and surprisingly, the second line of output is indented by roughly one tab. Why?
Here's the code:
With Ada.Text_IO;
Use Ada.Text_IO;
With Ada.Integer_Text_IO;
use Ada.Integer_Text_IO;
procedure Main is
N : Integer;
begin
-- Insert code here.
Put("Enter an integer value: ");
Get(N);
if N>0 then
Put (N);
Put_Line(" is a positive number");
end if;
end Main;
(how do I get syntax highlighting?)
Here is a sample of the output (the first 1 being input):
Enter an integer value: 1
1 is a positive number
The Put procedure from Ada.Integer_Text_IO uses a default field width padded with spaces.
The specification for that procedure is defined in the Ada Language Reference Manual as:
procedure Put(Item : in Num;
Width : in Field := Default_Width;
Base : in Number_Base := Default_Base);
The Width and Base parameters are given default values. Your call to Put only supplied a value for the formal parameter Item. To eliminate the left padding simply specify a desired width. I suggest you use Ada named notation for the call as in
Put(Item => N, Width => 1);
I read other questions about the "slice bounds of range" here in the stackoverflow, but none of them using the same context from this.
Then, none of the answers helped me.
In my use case, the "golang's syntax" of substring using [] doesn't return an error variable. It launches a runtime error using the "panic" instruction.
My goal is to avoid to reach on the "panic" instruction.
I need to treat this error and provide messages that describe with more details the context around the moment where this error had occurred.
Obs:
The content of the string variable which one I need to get the substring value is totally dynamic and the indexes that I have been using to get the substring value is equally calculated dynamically.
You need to do bounds checking on your indexes:
if j >= 0 && j <= len(str) {
y = str[:j]
}
I developed the following sorting algorithm but there are some run time errors that I cant figure out. The program terminates when it comes to the part of filling the array. I'm still a beginner in ada so I couldn't figure out where the problem is...
With Ada.Text_IO;
With Ada.Integer_Text_IO;
Use Ada.Integer_Text_IO;
Use Ada.Text_IO;
Procedure sort is
n,i,x : Integer;
-- Max_Heapify Function...
Procedure Max_Heapify ( i, n : integer) is
j, Temp : Integer;
begin
Temp:=Int_Acc(i);
j:=2*i;
if Temp>Int_Acc(j) then
elsif Temp<=Int_Acc(j) then
Int_Acc(j/2):=Int_Acc(j);
j:=2*j;
end if;
end loop;
Int_Acc(j/2):=Temp;
end Max_Heapify;
begin
Get(n);
for i in MyArr'range loop
Put_Line("Enter Element " & Integer'Image(i));
Get(MyArr(i));
end loop;
end;
end sort;
Thanks in advance :)
Your Problem is that you are insisting on writing Ada code using c - Style programming paradigms.
Firstly:
The declarations:
Type Arr is array(1..20) of Integer;
Type int_access is access Arr;
MyArr : int_access;
Where you use Int_Acc : in out int_access as parameters to procedures are useless in Ada. You are trying to pass a pointer to an array in (which you are doing!), but you should just pass your Type Arr as in out - The Ada compiler knows to do this as a pointer!
Secondly:
I cannot see where you actually allocate any memory to MyArr. This is a possible source of your runtime error. (when you write to or index an array that does not exist, i would expect to have a problem!)
Thirdly:
You seem to be mixing fixed length arrays with variable length input. If N > 20, you will have a problem.
Fourthly:
Insulting the language is not the best way of getting help from those who like it.
NWS has nailed it : there is a pointer, but no array there.
But it's clear that you have learned C, which leaves you with a lot to learn about other languages including Ada. There really are better ways of doing many things, that aren't taught to C programmers because C doesn't allow them.
Allocating variable sized arrays without pointers, malloc and free for example...
Type Arr is array(positive range <>) of Integer; -- of any size
begin
Put_Line("Enter Number Of Elements Of Array");
Get(n);
declare -- now we know the size
My_Arr : Arr(1 .. n);
begin -- My_Arr is in scope until the end of this block
...
end;
end sort;
Using the type system better...
Bad programming :
for i in 1 .. n loop
Get(MyArr(i));
end loop;
HeapSort(MyArr,n);
for i in 1 .. n loop
Put_Line(Integer'Image(MyArr(i)));
end loop;
This is bad because it violates the DRY principle : loop bounds repeated, and something that hopefully represents the array size passed around as a separate parameter... a maintenance nightmare if you decide to rename n to something meaningful for example.
better programming : Use the type system. Recognise that merely declaring an array has declared a new subtype of integer, representing the index of the array. You can access it as My_Arr'range, and the high bound as My_Arr'last.
for i in My_Arr'range loop
Get(MyArr(i));
end loop;
HeapSort(MyArr);
for i in My_Arr'range loop
Put_Line(Integer'Image(MyArr(i)));
end loop;
And accidents such as redefining n after the array declaration can no longer generate buffer overflows.
NOTE: Heapsort now gets its range from the array. (Max_Heapify may still need a separate parameter to operate on subsets of the array)
Arguably best - if it makes the intent clearer - name the index datatype explicitly and use it...
declare -- now we know the size
subtype My_Range is positive range 1 .. n;
My_Arr : Arr(My_Range);
begin -- My_Arr is in scope until the end of this block
for i in My_Range loop ...
And lastly, which do you prefer; a Storage_Error exception immediately the bug occurs (writing to memory you forgot to allocate) or something odd happening much later because something scribbled across another variable?
EDIT
Having cleared up the major issues two more subtle ones remain...
If I compile the modified program (in Gnat 4.8) I get several warnings : one of them is important and tells you exactly what the problem is...
Most of the warnings stem from the fact that
for i in My_Arr'range loop
declares its own loop variable i which hides any existing in-scope declaration. So you can tidy up the code by removing the unnecessary declarations.
What remains is:
sort.adb:51:28: warning: loop range may be null
sort.adb:51:28: warning: bounds may be wrong way round
The for loop bounds are empty ranges, reversed...
1 .. 3 declares a subtype with 3 values
reverse 1 .. 3 declares the same subtype and iterates backwards over it.
But 3 .. 1 declares an EMPTY subtype (containing NO valid values) so iterating over it - either way round - does precisely nothing.
Hopefully that is the missing part of the puzzle. I'm not clear why one faulty loop gets this warning while the other (at line 38) doesn't...
if j<n **and then** Int_Acc(j+1)>Int_Acc(j) then
j:=j+1;
I think you want just 'and' instead of 'and then,' although I haven't looked at Ada code in years.
Did that compile?
Upon creating an instance of a given ActiveRecord model object, I need to generate a shortish (6-8 characters) unique string to use as an identifier in URLs, in the style of Instagram's photo URLs (like http://instagram.com/p/P541i4ErdL/, which I just scrambled to be a 404) or Youtube's video URLs (like http://www.youtube.com/watch?v=oHg5SJYRHA0).
What's the best way to go about doing this? Is it easiest to just create a random string repeatedly until it's unique? Is there a way to hash/shuffle the integer id in such a way that users can't hack the URL by changing one character (like I did with the 404'd Instagram link above) and end up at a new record?
Here's a good method with no collision already implemented in plpgsql.
First step: consider the pseudo_encrypt function from the PG wiki.
This function takes a 32 bits integer as argument and returns a 32 bits integer that looks random to the human eye but uniquely corresponds to its argument (so that's encryption, not hashing). Inside the function, you may change the formula: (((1366.0 * r1 + 150889) % 714025) / 714025.0) with another function known only by you that produces a result in the [0..1] range (just tweaking the constants will probably be good enough, see below my attempt at doing just that). Refer to the wikipedia article on the Feistel cypher for more theorical explanations.
Second step: encode the output number in the alphabet of your choice. Here's a function that does it in base 62 with all alphanumeric characters.
CREATE OR REPLACE FUNCTION stringify_bigint(n bigint) RETURNS text
LANGUAGE plpgsql IMMUTABLE STRICT AS $$
DECLARE
alphabet text:='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
base int:=length(alphabet);
_n bigint:=abs(n);
output text:='';
BEGIN
LOOP
output := output || substr(alphabet, 1+(_n%base)::int, 1);
_n := _n / base;
EXIT WHEN _n=0;
END LOOP;
RETURN output;
END $$
Now here's what we'd get for the first 10 URLs corresponding to a monotonic sequence:
select stringify_bigint(pseudo_encrypt(i)) from generate_series(1,10) as i;
stringify_bigint
------------------
tWJbwb
eDUHNb
0k3W4b
w9dtmc
wWoCi
2hVQz
PyOoR
cjzW8
bIGoqb
A5tDHb
The results look random and are guaranteed to be unique in the entire output space (2^32 or about 4 billion values if you use the entire input space with negative integers as well).
If 4 billion values was not wide enough, you may carefully combine two 32 bits results to get to 64 bits while not loosing unicity in outputs. The tricky parts are dealing correctly with the sign bit and avoiding overflows.
About modifying the function to generate your own unique results: let's change the constant from 1366.0 to 1367.0 in the function body, and retry the test above. See how the results are completely different:
NprBxb
sY38Ob
urrF6b
OjKVnc
vdS7j
uEfEB
3zuaT
0fjsab
j7OYrb
PYiwJb
Update: For those who can compile a C extension, a good replacement for pseudo_encrypt() is range_encrypt_element() from the permuteseq extension, which has of the following advantages:
works with any output space up to 64 bits, and it doesn't have to be a power of 2.
uses a secret 64-bit key for unguessable sequences.
is much faster, if that matters.
You could do something like this:
random_attribute.rb
module RandomAttribute
def generate_unique_random_base64(attribute, n)
until random_is_unique?(attribute)
self.send(:"#{attribute}=", random_base64(n))
end
end
def generate_unique_random_hex(attribute, n)
until random_is_unique?(attribute)
self.send(:"#{attribute}=", SecureRandom.hex(n/2))
end
end
private
def random_is_unique?(attribute)
val = self.send(:"#{attribute}")
val && !self.class.send(:"find_by_#{attribute}", val)
end
def random_base64(n)
val = base64_url
val += base64_url while val.length < n
val.slice(0..(n-1))
end
def base64_url
SecureRandom.base64(60).downcase.gsub(/\W/, '')
end
end
Raw
user.rb
class Post < ActiveRecord::Base
include RandomAttribute
before_validation :generate_key, on: :create
private
def generate_key
generate_unique_random_hex(:key, 32)
end
end
You can hash the id:
Digest::MD5.hexdigest('1')[0..9]
=> "c4ca4238a0"
Digest::MD5.hexdigest('2')[0..9]
=> "c81e728d9d"
But somebody can still guess what you're doing and iterate that way. It's probably better to hash on the content