Finding minimum value more efficiently in racket - racket

Hello,
I am working on some Racket practice. I am aware that Racket has a built in min function, but I am trying to write one from scratch. I have done some work and found some ideas online, but the code is not very efficient. I am thinking I will need to use a helper method. I am a bit lost on how to further modify this code to make it efficient. I ran this code on the test case shown and it took way too long. On smaller test cases the code does return the correct results. Any suggestions would be great.
(define (minim lst)
(cond
((null? (cdr lst)) (car lst))
((< (car lst) (minim (cdr lst))) (car lst))
(else
(minim (cdr lst)))) )
(minim '(3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4))
Would return 1.

Assuming an unsorted list, the most natural way to find the minimum would be to go through the entire list, comparing each element against some initial min value, and whenever an element is smaller than that min, the element gets saved as the new min. At the end, min gets returned when list becomes empty (base case).
For example, consider the following:
(define (minimum lst acc)
(cond
((null? lst) acc)
((< (car lst) acc)
(minimum (cdr lst) (car lst)))
(else
(minimum (cdr lst) acc))))
(define (mymin lst)
(if (null? lst)
#f
(minimum (cdr lst) (car lst))))
mymin takes O(n) time to find min value in a list, using n-1 comparisons, where n is the number of elements in list.
You can test this with longer and shorter lists locally:
(mymin '(3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4
3 4 2 9 3 8 7 7 7 7 7 7 7 7 7 8 2 1 3 2 2 2 3 4 -1))
=> -1

The code runs longer than it needs to because for each item in the list, minim is called recursively on the cdr in the test condition. It has what known as tree recursion.
A more "Rackety" way to write minim might be to define a simple function that compares two numbers:
(define (min-of-2 x y)
(if (< x y)
x
y))
And then fold it over the list using foldl:
(define (minim lst)
(foldl min-of-2 (first lst) (rest lst)))
The time to use foldl is when an operation over a list produces a single value based on the contents of the list as is the case here.
The function min-of-2 need not be given a name and can be passed as a lamda. For example:
(define (minim lst)
(foldl
(lambda (x y) (if (< x y) x y))
(first lst)
(rest lst)))

Related

AMPL Group Qualified Assignment How to Fix Problem

set student;
set group;
var assign{i in student, j in group} binary;
param pref{i in student, j in group};
maximize totalPref:
sum{i in student, j in group} pref[i,j]*assign[i,j];
subject to exactly_one_group {i in student}:
sum {j in group} assign[i,j] =1;
subject to min3{j in group}:
sum{i in student} assign[i,j]>=3;
subject to max4{j in group}:
sum{i in student} assign[i,j]<=4;
##########
data;
set group:= A ED EZ G H1 H2 RB SC;
set student:= Allen Black Chung Clark Conners Cumming Demming Eng Farmer Forest Goodman Harris Holmes Johnson Knorr Manheim Morris Nathan Neuman Patrick Rollins Schuman Silver Stein Stock Truman Wolman Young;
param pref:
A ED EZ G H1 H2 RB SC:=
Allen 1 3 4 7 7 5 2 6
Black 6 4 3 5 5 7 1
Chung 6 2 3 1 1 7 5 4
Clark 7 6 1 2 2 3 5 4
Conners 7 6 1 3 3 4 5 2
Cumming 6 7 4 2 2 3 5 1
Demming 2 5 4 6 6 1 3 7
Eng 4 7 2 1 1 6 3 5
Farmer 7 6 5 2 2 1 3 4
Forest 6 7 2 5 5 1 3 4
Goodman 7 6 2 4 4 5 1 3
Harris 4 7 5 3 3 1 2 6
Holmes 6 7 4 2 2 3 5 1
Johnson 7 2 4 6 6 5 3 1
Knorr 7 4 1 2 2 5 6 3
Manheim 4 7 2 1 1 3 6 5
Morris 7 5 4 6 6 3 1 2
Nathan 4 7 5 6 6 3 1 2
Neuman 7 5 4 6 6 3 1 2
Patrick 1 7 5 4 4 2 3 6
Rollins 6 2 3 1 1 7 5 4
Schuman 4 7 3 5 5 1 2 6
Silver 4 7 3 1 1 2 5 6
Stein 6 4 2 5 5 7 1 3
Stock 5 2 1 6 6 7 4 3
Truman 6 3 2 7 7 5 1 4
Wolman 6 7 4 2 2 3 5 1
Young 1 3 4 7 7 6 2 5;
Suppose that you are allowed to assign up to two groups to un-qualified students. How would you reformulate the problem and find the new solution, with preference still applying? * means un-qualified
param pref: A ED EZ G H1 H2 RB SC:= Allen 1 3 * 7 7 5 * 6 Black 6 * 3 5 5 * 1 3 Chung 6 2 3 1 * 7 5 * Clark * 6 1 * 2 3 5 4 Conners 7 6 1 3 3 * * 2

How to exchange group of rows of a matrix in MATLAB?

I have a matrix A ,and vector x as following (left side)
where S0, H0,...is row number of each block. I want to exchange these blocks such that S0 and S1; H0 and H1 are near together as right side. This is my code
S0=3;
H0=2;
N0=2;
S1=4;
H1=5;
N1=4;
Cols=5;
Rows=S0+H0+N0+S1+H1+N1;
A=randi(10,[ Rows Cols]);
x=randi(10,[Rows 1]);
%% Exchange two block
temp=A(S0+H0+1:S0+H0+N0,1:end);
A(S0+H0+1:S0+H0+H1,1:end)=A(S0+H0+N0+S1+1:S0+H0+N0+S1+H1,1:end);
A(S0+H0+N0+S1+1:S0+H0+N0+S1+H1,1:end)=temp;
%% How exchange x
The above code is not work. How can I fixed it in MATLAB? Thank in advance.
One approach with mat2cell and cell2mat -
grps = [S0,H0,N0,S1,H1,N1]
new_pattern = [1 4 2 5 3 6]
celldata_roworder = mat2cell((1:size(A,1))',grps); %//'
newx = cell2mat(celldata_roworder(new_pattern)).'; %//'
newA = A(newx,:)
Sample run -
Input :
A =
6 8 9 8 7
4 8 8 3 4
3 8 2 1 10
5 2 6 8 3
5 7 4 7 7
4 5 6 8 7
6 3 4 7 4
8 1 5 5 2
5 9 2 4 1
5 2 3 9 5
2 2 1 4 2
1 7 10 9 8
3 9 7 8 4
4 6 10 9 9
7 8 2 6 8
10 2 10 7 6
10 10 8 10 2
5 6 6 5 10
3 7 5 1 3
8 1 3 9 10
grps =
3 2 2 4 5 4
new_pattern =
1 4 2 5 3 6
Output:
newx =
1 2 3 8 9 10 11 4 5 12 ...
13 14 15 16 6 7 17 18 19 20
newA =
3 3 2 5 8
4 3 3 7 7
1 5 2 8 1
4 6 4 1 4
7 1 5 8 8
4 9 10 10 8
7 10 10 4 3
7 3 1 6 9
2 9 2 6 10
1 1 7 10 3
10 10 10 4 7
9 1 8 9 5
8 7 4 5 7
9 8 7 5 3
1 10 7 6 8
8 1 10 6 1
4 6 3 3 2
7 9 3 2 9
6 9 7 4 8
6 7 6 8 10
I assume you are using a 2-dimensional matrix with Row rows and Cols columns.
You can use the colon : as a second index to address a full row, e.g. for the third row:
A(3, :)
(equal to A(3, 1:end) but little bit clearer).
So you could split your matrix into lines and re-arrange them like this (putting back together the lines to a two-dimensional matrix):
A = [ A(3:4, :); A(1:2, :); A(5:end, :) ]
This moves rows 3 and 4 at the beginning, then old lines 1 and 2 and then all the rest. Does this help you?
Hint: you can use eye for experimenting.

knnclassify and knnsearch give different results

I'm using knnclassify to do a kNN classification in Matlab and it's working well. Now, I need to know the distances to the neighbors and it seems that knnsearch funcion gives me that.
The problem is the results are not the same. I am quite sure knnsearch is not working properly, but I don't know the reason.
This is my code:
k=1;
distance='euclidean';
rule='nearest';
%kNN classification
result = knnclassify(sample_matrix, training_matrix, label_matrix,k,distance,rule);
%showing which element is recognized and the distance to it
[recognition,distances] = knnsearch(training_matrix, sample_matrix,'k',k);
So, result and recognition should be the same, and then I can see the distances.
This is result:
4 1 1 2 4 1 1 4 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 2 3 3 3 3 3 3 4 4 4 4 4
4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7
8 8 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 9
And this is recognition:
3 1 1 2 3 1 1 3 1 1 2 2 1 2 2 2 1 2 2 2 2 2 2 2 2 2 2 3 2 2 4 3 3 4 3
4 4 3 3 3 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 6 6 6 5 5 6 6 6
7 6 6 6 6 7 6 6 6 7 8 7 7 7 7 7 7 7 7 7
(They're supposed to be two vectors).
The desired result is
1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4
4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8
8 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 9
So, result is almost well (good enough) and recognition is a disaster.
As you can see the beginning is much better than the end.
Anybody can help me??
Thank you very much.

replace blank column with word

I have a text file some of the record is blank and I want replace that blank space with the word N/A or null
ex-
field-A field-b field-c field-d field-e field-f field-g field-h field-i
1 2 3 4 5 6 7 8 9
1 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9
1 4 5 6 7 8 9
result expect
field-A field-b field-c field-d field-e field-f field-g field-h field-i
1 2 3 4 5 6 7 8 9
1 N/A 3 4 5 6 7 8 9
N/A 2 3 4 5 6 7 8 9
1 N/A N/A 4 5 6 7 8 9
perl -pe 's/ / x / while / /' <<END
1 2 3 4 5 6 7 8 9
1 3 4 5 6 7 8 9
2 3 4 5 6 7 8 9
1 4 5 6 7 8 9
END
produces
1 2 3 4 5 6 7 8 9
1 x 3 4 5 6 7 8 9
x 2 3 4 5 6 7 8 9
1 x x 4 5 6 7 8 9
If it's a space character I'd look for the character code or a blank space.
In C# assuming your variable was mystr it would be something like:
myStr = myStr.Replace(" ", "N/A");
You can also look for the character value, depending on the language you're using.

MATLAB: Filling a matrix with each column being the same

I am trying to create a matrix that is 3 x n, with each of the columns being the same. What's the easiest way of achieving it? Concatenation?
After
n=7
x=[1;2;3]
it's either
repmat(x,[1 n])
or
x(:,ones(1,n))
(Octave can be considered as an open source/free version of MATLAB)
octave-3.0.3:2> rowvec = [1:10]
rowvec =
1 2 3 4 5 6 7 8 9 10
octave-3.0.3:3> [rowvec; rowvec; rowvec]
ans =
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Use repmat if the number of rows is large.
octave-3.0.3:7> repmat(rowvec, 10, 1)
ans =
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Use multiplication with a 1 x 3 matrix of ones
eg, x * [1 1 1]
Edit:
In Octave:
octave-3.0.3.exe:1> x = [1;2;3;4]
x =
1
2
3
4
octave-3.0.3.exe:5> x * [1 1 1]
ans =
1 1 1
2 2 2
3 3 3
4 4 4