Need help in Reading contents of memory array and get a count in vhdl - process

input array: Ram = {D D D D D 3 3 3 3 7 7 7 9 9 8 8};
I am expecting the output as below:
Count = {0 0 0 4 0 0 0 3 2 2 0 0 0 5 0 0};
That is to count the number of occurances, like there are five D's , four 3's , three 7's, two 9's and two 8's so that Count array has 5 in Dth index, 4 in 3rd index, 3 in 7th index and so on.
my code is as below:
architecture behav of Bitcount is
signal cnt: count_type := (others=> (others=>'0'));
use ieee.numeric_std.all;
begin
Countproc:process(clk)
begin
if (clk'event and clk='1' ) then
if Enable='1' then
if (Read_bit='1') then
for k in 0 to 15 loop
for i in 0 to 15 loop
if ( Ram(k) = std_logic_vector(to_unsigned(i, 4)) )then
cnt(i) <= cnt(i) + "01";
end if;
end loop;
end loop;
end if;
end if;
Count <= cnt;
end if;
end process Countproc;
end behav;
but its not working as my expectation . pls help

Your problem is that cnt is a signal. It needs to be a variable.
The lines of code within a process are executed sequentially. Whenever a line of code containing a signal assignment (<=) is executed, an event is put on the event queue to drive the target signal (cnt in this case) on the next delta cycle (assuming there is some change to the target signal as a result). The event queue is the simulator's "to do" list; a delta cycle is one iteration of the simulator; the next iteration will occur once all the processes that are executing in the current iteration suspend.
If, during any execution of a process, another signal assignment to the same target signal is encountered, then (usually*) any other events on the event queue relating to that signal are deleted. So, in your example, every time this line is encountered (which it will be 16*16=256 times):
cnt(i) <= cnt(i) + "01";
Instead of incrementing cnt(i) (which is what I assume you are expecting to happen), all previous events relating to cnt(i) are deleted and replaced with a new event to drive cnt(i) with the value it had before the process started executing plus one. The signal cnt(i) does not get its new value until the process completes executed (and all other processes too).
Variables do not exhibit this behaviour; variables behave just like variables do in any software language. When a line of code is encountered with a variable assignment (:=), the variable is updated immediately and so its value is immediately available for further calculations.
So, how about changing cnt to a variable:
architecture behav of Bitcount is
use ieee.numeric_std.all;
begin
Countproc:process(clk)
variable cnt : count_type;
begin
if (clk'event and clk='1' ) then
if Enable='1' then
if (Read_bit='1') then
cnt := (others=> (others=>'0'));
for k in 0 to 15 loop
for i in 0 to 15 loop
if ( Ram(k) = std_logic_vector(to_unsigned(i, 4)) )then
cnt (i) := cnt (i) + "01";
end if;
end loop;
end loop;
Count <= cnt;
end if;
end if;
end if;
end process Countproc;
end behav;
I can't be sure this will work, because you haven't provided an MCVE, so I haven't tested it. But you original solution will not work for the reason I have given.
--
* this is nearly always true, because of the way that VHDL models delays as inertial delays and it is certainly true in this example. But strictly it's not always true.

Related

Getting ORA-10028 with DBMS_OUTPUT.PUT even with small chunk size?

I need to get a DBMS_OUTPUT that has an extensive length (60K+ characters). I understand the limit is 32767, but the issue for me with using the common LOOP solution...
LOOP
EXIT WHEN OUTPUT_OFFSET > DBMS_LOB.GETLENGTH(VAROUTT);
DBMS_OUTPUT.PUT_LINE(DBMS_LOB.SUBSTR(VAROUTT, OUTPUT_CHUNKS, OUTPUT_OFFSET));
OUTPUT_OFFSET := OUTPUT_OFFSET + OUTPUT_CHUNKS;
END LOOP;
... is that my string already contains new lines based on the calculation that is being done within the procedure. With PUT_LINE I'm getting the following (yellow) due to the PUT_LINE size:
So I need to make use of PUT, to ensure it's my procedure the one that determines when a NEW_LINE is to be inserted. I tried the following:
LOOP
EXIT WHEN OUTPUT_OFFSET > DBMS_LOB.GETLENGTH(VAROUTT);
DBMS_OUTPUT.PUT(DBMS_LOB.SUBSTR(VAROUTT, OUTPUT_CHUNKS, OUTPUT_OFFSET));
OUTPUT_OFFSET := OUTPUT_OFFSET + OUTPUT_CHUNKS;
END LOOP;
The only difference is that I'm calling command "PUT" instead of "PUT_LINE", to prevent my output from performing irrelevant new-line calls. The issue is that I'm getting error:
ORU-10028: line length overflow, limit of 32767 bytes per line.
This happens only if I use PUT instead of PUT_LINE, even if my chunk size is 10. My initial setup is:
SET SERVEROUTPUT ON SIZE UNLIMITED;
SET LINESIZE 200;
Not sure if the LINESIZE setup is relevant, still 200 is bigger than 10. Each line doesn't surpass 50 characters.
LINESIZE is a sqlplus parameter that wraps text in the display; it has no bearing on PL/SQL code.
By definition, DBMS_OUTPUT.PUT "places a partial line in the buffer." It doesn't matter how you set up your chunk size because you're just appending into the same 32K line limit. You must call DBMS_OUTPUT.NEW_LINE or DBMS_OUTPUT.PUT_LINE to introduce separate lines.
Note that DBMS_OUTPUT is generally used for debugging messages, and not large-scale text reporting.
my string already contains new lines
You can split your string on those newline characters (assuming each of those lines is then less than 32k, which seems to be the case - you said they're less than 50 characters each); i.e. varying OUTPUT_CHUNKS each time, and reading each chunk (minus its own newline) into a string buffer that you then print with put_line(). Something like:
...
BUFFER varchar2(32767);
...
WHILE OUTPUT_OFFSET < DBMS_LOB.GETLENGTH(VAROUTT) LOOP
-- read to next newline if there is one, rest of CLOB if not
IF dbms_lob.instr(VAROUTT, chr(10), OUTPUT_OFFSET) > 0 then
OUTPUT_CHUNKS := dbms_lob.instr(VAROUTT, chr(10), OUTPUT_OFFSET) - OUTPUT_OFFSET;
dbms_lob.read(VAROUTT, OUTPUT_CHUNKS, OUTPUT_OFFSET, BUFFER);
OUTPUT_OFFSET := OUTPUT_OFFSET + OUTPUT_CHUNKS + 1; -- skip newline character
ELSE
OUTPUT_CHUNKS := 32767;
dbms_lob.read(VAROUTT, OUTPUT_CHUNKS, OUTPUT_OFFSET, BUFFER);
OUTPUT_OFFSET := OUTPUT_OFFSET + OUTPUT_CHUNKS;
END IF;
dbms_output.put_line(BUFFER);
END LOOP;
You could store DBMS_LOB.GETLENGTH(VAROUTT) in a variable to avoid recalculating that thousands of times.

Removing Duplicates from json_array_t

Currently i have two for loops that push ids into two separate json_array_t such as
[123,124,125,126]
[123,126,127]
I want to combine these two json_array_t into one and remove duplicates so it results in
[123,124,125,126,127]
to push ids from one json_array_t to another im doing this
ja_id1.put(1,id2,false);
But this puts all ids into one and keeps duplicates, and im not sure how to remove duplicates, thanks.
Check for duplicates before adding the value:
DECLARE
arr1 JSON_ARRAY_T := JSON_ARRAY_T.PARSE('[123,124,125,126]');
arr2 JSON_ARRAY_T := JSON_ARRAY_T.PARSE('[123,126,127]');
BEGIN
<<outer_loop>>
FOR i IN 0 .. arr2.get_Size - 1
LOOP
FOR j IN 0 .. arr1.get_size - 1
LOOP
IF arr1.get_number(j) = arr2.get_number(i) THEN
CONTINUE outer_loop;
END IF;
END LOOP;
arr1.append(arr2.get_number(i));
END LOOP;
FOR i IN 0 .. arr1.get_Size - 1
LOOP
DBMS_OUTPUT.PUT_LINE(arr1.get_number(i));
END LOOP;
END;
/
Which outputs:
123
124
125
126
127
db<>fiddle here

FIle handling in Eiffel

Given a file input.txt, which consists of a number of elements in arrays and elements in the arrays, I should read the data and copy it to arrays in Eiffel. For example, for
3
3 4 5
2 3 1
I should get len = 3, a1 = {3,4,5}, a2 = {2,3,1}.
I have tried the following but it was not successful
take_input
-- Read user's input.
local
input: PLAIN_TEXT_FILE
output: PLAIN_TEXT_FILE
itr: INTEGER
do
create input.make_open_read ("input.txt")
input.read_integer
len := input.last_integer
create output.make_open_write ("output.txt")
create num.make_filled (0, 1, len)
create rem.make_filled (0, 1, len)
from
input.start
input.read_integer
itr := 0
until
input.off
loop
itr := itr + 1
if itr <= len then
num [itr] := input.last_integer
input.read_integer
else
rem [itr - len] := input.last_integer
input.read_integer
end
end
input.close
end
Here Is there any way I can continously read the inputs rather than again starting from the Begginning of the file?
There is no need to go to the beginning of the file after reading the number of elements. Therefore, removing input.start right after from will do the trick.
As a sanity check (in case it matters for your program), it makes sense to test whether len is positive before starting the loop.

SAS running out of memory when trying to do fuzzy matching using hash tables on a small sample dataset

I have a list of names, phone numbers, and addresses with ~5,000,000 rows. I am trying to create a list of unique customers at each address with each unique customer being assigned a key. The customer names are not formatted consistently, so John Smith might appear as, e.g., Smith, John, or John Smith Jr., etc.
The logic I want to follow is this:
If two records at an address have the same phone number, it's the same customer, whether they have different names or not, and get assigned the same customer_key.
If two records at an address don't have the same phone number (or have no phone number), but a fuzzy match on their names exceeds some threshold, they are the same customer, and get assigned the same customer_key.
Note that the same customer name + phone number match at two separate addresses should not be assigned the same customer key.
Here are example tables containing sample input and desired output:
https://docs.google.com/spreadsheets/d/1RsABSFy5a5dLE8mC-ZQF_lNg4I0kLQy7dEFhbfovq40/edit?usp=sharing
My code attempt using this sample dataset is below:
data customer_keys(keep=customer_name customer_key customer_phone clean_address);
length customer_name $50 Comp_Name $20 customer_key 8 clean_address comp_address $5 customer_phone comp_phone $11.;
if _N_ = 1 then do;
declare hash h(multidata:'Y');
h.defineKey('Comp_Name','comp_address');
h.defineData('Comp_Name', 'customer_key','comp_address', 'comp_phone');
h.defineDone();
declare hiter hi('h');
declare hash hh(multidata:'Y');
hh.defineKey('customer_key');
hh.defineData('customer_key', 'Comp_Name','comp_address','comp_phone');
hh.defineDone();
_customer_key=0;
end;
set testdat;
rc=h.find(key:customer_name, key:clean_address);
if rc ne 0 then do;
rc=hi.first();
do while (rc=0);
if not missing(customer_phone) and clean_address=comp_address and customer_phone=comp_phone
then do;
h.add(key:customer_name,key:clean_address, data:customer_name, data:customer_key, data:clean_address, data:customer_phone);
hh.add();
end;
else if not missing(customer_name) and clean_address=comp_address and jaroT(customer_name,Comp_name) ge 0.8
then do;
rc=hh.find();
do while (r ne 0);
dist2=jaroT(customer_name,Comp_name);
hh.has_next(result:r);
if r=0 & dist2 ge 0.8 then do;
h.add(key:customer_name,key:clean_address, data:customer_name, data:customer_key, data:clean_address, data:customer_phone);
hh.add();
output;return;
end;
else if r ne 0 & dist2 ge 0.8
then rc=hh.find_next();
else if dist2 < 0.8
then leave;
end;
end;
rc=hi.next();
end;
_customer_key+1;
customer_key=_customer_key;
h.add(key:customer_name,key:clean_address, data:customer_name, data:customer_key, data:clean_address, data:customer_phone);
hh.add(key:customer_key, data:customer_key, data:customer_name, data:clean_address, data:customer_phone);
end;
output;
run;
Running this code yields the error:
ERROR: Hash object added 23068656 items when memory failure occurred.
FATAL: Insufficient memory to execute DATA step program. Aborted during the EXECUTION phase.
ERROR: The SAS System stopped processing this step because of insufficient memory.
I notice that if I remove the additional logic dealing with the phone number entirely, I don't have this memory issue. However I am still going to assume that my approach will fail either way because of lack of memory when I try to run it on the full dataset.
search for "sas.exe-memsize 16G" in your windows search function to pull a new version of sas program that will have 16G in memory storage. You can change the number before G, too. Also make sure you have enough disk space. Cheers.
I managed to solve the memory issue and now the code is working as expected! The error was in the section dealing with matching phone numbers. The corrected code is below:
data test customer_keys(keep=customer_name customer_key customer_phone clean_address);
length customer_name $50 Comp_Name $20 customer_key 8 clean_address comp_address $22 customer_phone comp_phone $14.;
if _N_ = 1 then do;
declare hash h(multidata:'Y');
h.defineKey('Comp_Name','comp_address');
h.defineData('Comp_Name', 'customer_key','comp_address', 'comp_phone');
h.defineDone();
declare hiter hi('h');
declare hash hh(multidata:'Y');
hh.defineKey('customer_key');
hh.defineData('customer_key', 'Comp_Name','comp_address','comp_phone');
hh.defineDone();
_customer_key=0;
end;
set testdat;
rc=h.find(key:customer_name, key:clean_address);
if rc ne 0 then do;
rc=hi.first();
do while (rc=0);
if not missing(customer_phone) and clean_address=comp_address and customer_phone=comp_phone
then do;
rc=hh.find();
do while (r ne 0);
hh.has_next(result:r);
if r=0 then do;
h.add(key:customer_name,key:clean_address, data:customer_name, data:customer_key, data:clean_address, data:customer_phone);
hh.add();
output;return;
end;
else leave;
end;
end;
if not missing(customer_name) and clean_address=comp_address and jaroT(customer_name,Comp_name) ge 0.8
then do;
rc=hh.find();
do while (r ne 0);
dist2=jaroT(customer_name,Comp_name);
hh.has_next(result:r);
if r=0 & dist2 ge 0.8 then do;
h.add(key:customer_name,key:clean_address, data:customer_name, data:customer_key, data:clean_address, data:customer_phone);
hh.add();
output;return;
end;
else if r ne 0 & dist2 ge 0.8
then rc=hh.find_next();
else if dist2 < 0.8
then leave;
end;
end;
rc=hi.next();
end;
_customer_key+1;
customer_key=_customer_key;
h.add(key:customer_name,key:clean_address, data:customer_name, data:customer_key, data:clean_address, data:customer_phone);
hh.add(key:customer_key, data:customer_key, data:customer_name, data:clean_address, data:customer_phone);
end;
output;
run;
Also below I am posting the code for the jaroT function so that others can use it if they'd like, I didn't write this function, and you could substitute it in my code above with any comparison algorithm you'd like (be sure to also change the threshold numbers):
FUNCTION jaroT(string_1 $,string_2 $);
if STRING_1=STRING_2 THEN return(1);
else do;
length1=length(string_1);
if length1>26 then length1=26;
length2=length(string_2);
if length2>26 then length2=26;
range=(int(max(length1,length2)/2)-1);
big=max(length1,length2);
short=min(length1,length2);
array String1{26} $ 1 _temporary_;
array String2{26} $ 1 _temporary_;
array String1Match{26} $ 1 _temporary_;
array String2Match{26} $ 1 _temporary_;
/*The following two do loops place the characters into arrays labelled string1 and string2.
While we are here, we also set a second array of the same dimensions full of zeros. This will
act as our match key, whereby values in the same relative position as those in the original string
will be set to 1 when we find a valid match candidate later on.*/
do i=1 to length1 by 1;
String1{i}=substr(string_1,i,1);
String1Match{i}='0';
end;
do i=1 to length2 by 1;
String2{i}=substr(string_2,i,1);
String2Match{i}='0';
end;
/*We introduce m, which will keep track of the number of matches */
m=0;
/*We set a loop to compare one string with the other. We only need to loop the same number of
times as there are characters in one of our strings. Hence "do while i<=length1".
We set the allowable search range for a character using pos and endpos, and set another loop to
search through this range. We loop through until we find our first match, or until we hit
the end of our search range. If the character in string 2 is already signed to a match, we move
on to searching the next character. When we find a match, the match flag for that character in both
strings is set to 1. Hopefully by the end of the loop, we have match flags for our two arrays set.
*/
do i=1 to length1 by 1;
pos=max(i-range,1);
endpos=min(range+i,length2);
do while (pos<=endpos and String1Match{i}^='1');
if String1{i}=String2{pos} and String2Match{pos}^='1' then do;
m=m+1;
String1Match{i}='1';
String2Match{pos}='1';
end;
pos=pos+1;
end;
end;
/* If there are no matching characters, we do not bother with any more work, and say the two strings are not alike at all */
IF m=0 then return(0);
else if m=1 then do;
t=0;
end;
/* If those three conditions all fail, then we move onto the heavy lifting.*/
else do;
/* We set i back to 1, ready for another looping run.
c is a variable to track the position of the next valid transposition check.
j is a variable helping to keep track of matching characters found during the next loop inside string 1.
k is a variable helping to keep track of matching characters found during the next loop inside string 2.
t will be the number of tranpositions found.
*/
i=1;
c=1;
k=0;
j=0;
t=0;
/* We begin our loop. These conditional loops within loops
make several logical conclusions to arrive at the correct number of transpositions and matching characters
at the beginning of a string. At the end of this we should have every variable we need to calculate the winkler
score (and theoretically the jaro as well). I'm not going to write out an explanation here, but if you're
interested all the extra variables are defined just above this comment, and I've already told you what the
string arrays are. Work through a couple of examples with pen and paper, or in your head, to see how
and why it works.*/
do while (j<m OR k<m);
IF j<m then do;
IF String1Match{i}='1' THEN DO;
j=j+1;
String1{j}=String1{i};
end;
end;
IF k<m then do;
IF String2Match{i}='1' THEN DO;
k=k+1;
String2{k}=String2{i};
end;
end;
IF j>=c and k>=c then do;
IF String1{c}^=String2{c} then t=t+1;
c=c+1;
end;
i=i+1;
end;
end;
/* Finally, we do the calculation of the scores */
jaro=(1/3)*((m/length1)+(m/length2)+((m-(t/2))/m));
return(jaro);
end;
endsub;
FUNCTION fuzznum(num_1,num_2,diff,direction);
IF direction=-1 THEN DO;
IF num_1-num_2<=diff AND num_1-num_2>=0 THEN RETURN(1);
ELSE RETURN(0);
END;
IF direction=1 THEN DO;
IF num_1-num_2>=-(diff) AND num_1-num_2<=0 THEN RETURN(1);
ELSE RETURN(0);
END;
IF direction=0 THEN DO;
IF ABS(num_1-num_2)<=diff THEN RETURN(1);
ELSE RETURN(0);
END;
endsub;

Semaphore in Ada

This is an assignment and I have been asked to implement a Semaphore in Ada as the description below.
However I have implemented the Semaphore.adb and called this Semaphore in the producerconsumer_sem.adb which I created.
I get some output which is the following.
I'm not sure if my initialization of semaphore is correct S: CountingSemaphore(1,1);.
I don't know where I call the S.wait and S.Signal now i randomly called the S.wait before Producer put item in the buffer X := I; and the S.Signal after the X := I;.
Is this the correct way?
Producer-Consumer Problem
The program producerconsumer.adb implements a non-reliable implemen-
tation of the producer-consumer problem, where data is likely be lost. In
the following, you will use three different communication mechanisms to
achieve a reliable implementation of the producer-consumer problem.
Semaphore
The Ada language does not directly provide library functions for a semaphore.
However, semaphores can be implemented by means of a protected object. Create a package specification Semaphore in the file Semaphores.ads
and the corresponding package body in the file Semaphores.adb that
implements a counting semaphore. Skeletons for the package are available on the course page.
Use the semaphore package for a reliable implementation of the producer-
consumer problem. Modify the file producerconsumer.adb and save the
final code as producerconsumer_sem.adb. In order to use the semaphore
package it shall be installed in the same directory as producerconsumer_sem.adb.
It can then be accessed by
with Semaphores;
use Semaphores;
The Output:
OutPut:
1
1
1
2
2
3
4
4
5
6
6
7
7
8
9
9
9
10
11
11
11
12
12
13
13
13
14
15
15
16
16
17
18
18
18
19
20
20
21
21
22
22
23
24
24
24
24
25
25
26
27
27
28
29
29
30
30
31
31
32
32
33
33
33
34
35
35
35
36
36
37
37
37
38
38
38
39
40
40
40
The package
package Semaphores is
protected type CountingSemaphore(Max: Natural; Initial: Natural) is
entry Wait;
entry Signal;
private
Count : Natural := Initial;
MaxCount : Natural := Max;
end CountingSemaphore;
end Semaphores;
The Semaphore I implemented semaphores.adb.
package body Semaphores is
protected body CountingSemaphore is
entry Wait when Count > 0 is
begin
Count := Count - 1;
end Wait;
entry Signal when Count < MaxCount is
begin
Count := Count + 1;
end Signal;
end CountingSemaphore;
end Semaphores;
The producerconsumer_sem.adb
with Ada.Text_IO;
use Ada.Text_IO;
with Ada.Real_Time;
use Ada.Real_Time;
with Ada.Numerics.Discrete_Random;
with Semaphores;
use Semaphores;
procedure ProducerConsumer_sem is
X : Integer; -- Shared Variable
N : constant Integer := 40; -- Number of produced and comsumed variables
S: CountingSemaphore(1,1);
--S1: CountingSemaphore(1,1);
pragma Volatile(X); -- For a volatile object all reads and updates of
-- the object as a whole are performed directly
-- to memory (Ada Reference Manual, C.6)
--Random Delays
subtype Delay_Interval is Integer range 50..250;
package Random_Delay is new Ada.Numerics.Discrete_Random
(Delay_Interval);
use Random_Delay;
G : Generator;
task Producer;
task Consumer;
task body Producer is
Next : Time;
begin
Next := Clock;
for I in 1..N loop
-- Write to X
S.Wait;
X := I;
S.Signal;
--Next 'Release' in 50..250ms
Next := Next + Milliseconds(Random(G));
Put_Line(Integer'Image(X));
delay until Next;
end loop;
end;
task body Consumer is
Next : Time;
begin
Next := Clock;
for I in 1..N loop
-- Read from X
S.Wait;
Put_Line(Integer'Image(X));
S.Signal;
Next := Next + Milliseconds(Random(G));
delay until Next;
end loop;
end;
begin -- main task
null;
end ProducerConsumer_sem;
On macOS, with FSF GCC 7.1.0 and GNAT GPL 2017, I changed your Put_Lines to Puts and got pretty-much the answer you state in the question.
The question says to create Semaphore.ads, .adb. This will work on Windows, and may work on macOS, but won’t work on Linux, because of GNAT’s file naming convention (see the end of this; it’s a good idea to get into the habit of using lower-case file names).
If you want to ensure that only one task has access to X at a time, I don’t think there’s much wrong with your Wait, Signal calls, though when I put a delay 0.1 at the beginning of Producer, the first value output was 151619216 (because X isn’t initialized). However! if the point is to communicate one update to X at a time (as implied by the names producer/consumer), you should
initialize the semaphore with a count of 0 (and a max of 1). This makes it a binary semaphore.
in Consumer, Wait only (i.e. remove the Signal)
in Producer, Signal only (i.e. remove the Wait). Also, remove the Put to avoid confusion!