postgresql create function Euclidean distance n dimensions - postgresql

I am noob in postgresql and I am trying to create a function to calculate the distances between a specific value and a set of values(records). Here is the table:
CREATE TABLE test
(
id serial NOT NULL,
name text,
values real[]
)
I want to create a function but I can't figure out how to loop every element in values[]
For example, I would like to select the name with the smallest distance. I didn't find any built-in function for this purpose.
I wrote the code in c# of what I am looking for:
List<double> res = new List<double>();
List<double[]> listDataBase=new List<double[]>();
double[] query = new double[] {12, 13, 13, 121};
double[] b = new double[] { 121, 1, 12, 124 };
double[] c = new double[] { 123, 123, 15, 122 };
double[] d = new double[] { 121, 1, 12, 124 };
double[] e = new double[] { 123, 123, 15, 122 };
listDataBase.Add(b);
listDataBase.Add(c);
listDataBase.Add(d);
listDataBase.Add(e);
foreach (double[] k in listDataBase)
{
double sum = 0;
for (int i = 0; i < query.Length; i++)
{
sum += Math.Pow(query[i] - k[i], 2);
}
res.Add(Math.Sqrt(sum));
}
res.Sort();

First I would change the name of the column you called values to vals. values is a keyword ofcourse you can write "values" in your queries but I would prefer to circumvent that issue by changing the name.
If I understand your question correctly I think it would be enough in your case to create a distance function then use that in a query. Here is the function:
CREATE OR REPLACE FUNCTION distance(l real[], r real[]) RETURNS real AS $$
DECLARE
s real;
BEGIN
s := 0;
FOR i IN 1..4 LOOP
s := s + ((l[i] - r[i]) * (l[i] - r[i]));
END LOOP;
RETURN |/ s;
END;
$$ LANGUAGE plpgsql;
If you want the name of the closest the query is:
SELECT name
FROM test
ORDER BY distance(test.values, ARRAY[12, 13, 13, 121]) DESC
LIMIT 1

Related

Shortening a dist style constraint in SystemVerilog

I have a constraint of the form:
s dist {0:= 20, 1:= 25, 2:= 30, <many more, possibly hundreds>};
Instead of writing down the constraint this way, I found in my application the RHS (i.e. the weights - 20, 25, 30, etc,) could come from an array my_array whose i-th element contains the weight for the i-th element.
Is there any way to shorten it to something like below? This is just to show the concept and is syntactically incorrect:
s dist {foreach rhsArray[j] {j: rhsArray}};
One brute-force approach is populating an array with each value appearing the number of times the weight of each element.
module top;
typedef int unsigned uint;
class A;
uint my_array[$];
uint rhsArray[] = {20, 25, 30, 25};
rand uint s,index;
function new;
foreach(rhsArray[j]) repeat (rhsArray[j]) my_array.push_back(j);
endfunction
constraint curve {
s == my_array[index];
index < my_array.size;
}
endclass
A a = new;
uint my_dist[uint] = '{default:0};
initial begin
repeat(10000) begin
assert(a.randomize);
my_dist[a.s]++;
end
$display("%p",my_dist);
end
endmodule
There is another variation of this where you construct an array of structures with ranges based on the weights (i.e. range[0]: 0-19, range[1]: 20-44, range[2]: 45-74, range[3]: 75-99). Then pick a random number between 0-99 and the number that is inside the range[j] becomes j==s.
A more convoluted approach is creating a another class for each element, where each element has a distribution for being picked or not.
class element;
uint weight, sum;
rand bit picked;
constraint d { picked dist {0:=sum, 1:= weight}; }
endclass
class A;
uint rhsArray[] = {20, 25, 30, 25};
rand element e[];
rand uint s,index;
function new;
uint sum = rhsArray.sum();
e = new[rhsArray.size];
foreach(rhsArray[j]) begin
e[j] = new;
e[j].weight = rhsArray[j];
e[j].sum = sum;
end
endfunction
constraint curve {
e.sum() with (uint'(item.picked)) == 1;
foreach(e[j]) e[j].picked -> j == s;
}
endclass

How to increment MongoDB id sequence from a specific number in Spring Boot?

Here is my code it increments from 1. but I want to start the id number from 100 and increment 1, for example 100, 101, 102, 103.
public int generateSeq(String seqname) {
Query query = new Query(Criteria.where("_id").is(seqName));
Update update = new Update().inc("seq", 1);
Dbseq counter = mongoOperations.findAndModify(query, update, options().returnNew(true).upsert(true), DbSeq.class);
return !Objects.isNull(counter) ? counter.getSeq() : 1;
}
I changed the number from 1 in inc function to 100 instead of 100, 101,102 etc; it prints 100,200,300. Can you let me know what is mossing here?

Reduce length of the pseudo-encrypt function ouput

i have a question about the pseudo-encrypt function for postgres.
Is there any way that I can reduce the output to 6? I really like this function and want to use it, but only need a output between 1 and 999999.
This question is related to my last question. I want to use it to created unqiue numbers between 1 and 999999.
Thank you.
Use mod on the generated value to generate number in range from start_value to end_value:
select start_value + mod(pseudo_encrypt(number), end_value - start_value + 1);
For your case this will be look like:
select 1 + mod(pseudo_encrypt(23452), 999999);
It's not quite straightforward to set an upper bound of 999999, as the algorithm operates on blocks of bits, so it's hard to get away from powers of two.
You can work around this by cycle walking - just try encrypt(n), encrypt(encrypt(n)), encrypt(encrypt(encrypt(n)))... until you end up with a result in the range [1,999999]. In the interest of keeping the number of iterations to a minimum, you want to adjust the block size to get you as close to this range as possible.
This version will let you specify a range for the input/output:
CREATE OR REPLACE FUNCTION pseudo_encrypt(
value INT8,
min INT8 DEFAULT 0,
max INT8 DEFAULT (2^62::NUMERIC)-1
) RETURNS INT8 AS
$$
DECLARE
rounds CONSTANT INT = 3;
L INT8[];
R INT8[];
i INT;
blocksize INT;
blockmask INT8;
result INT8;
BEGIN
max = max - min;
value = value - min;
IF NOT ((value BETWEEN 0 AND max) AND (max BETWEEN 0 AND 2^62::NUMERIC-1)) THEN
RAISE 'Input out of range';
END IF;
blocksize = ceil(char_length(ltrim(max::BIT(64)::TEXT,'0'))/2.0);
blockmask = (2^blocksize::NUMERIC-1)::INT8;
result = value;
LOOP
L[1] = (result >> blocksize) & blockmask;
R[1] = result & blockmask;
FOR i IN 1..rounds LOOP
L[i+1] = R[i];
R[i+1] = L[i] # ((941083981*R[i] + 768614336404564651) & blockmask);
END LOOP;
result = (L[rounds]::INT8 << blocksize) | R[rounds];
IF result <= max THEN
RETURN result + min;
END IF;
END LOOP;
END;
$$
LANGUAGE plpgsql STRICT IMMUTABLE;
I can't guarantee its correctness, but you can easily show that it maps [1,999999] back to [1,999999]:
SELECT i FROM generate_series(1,999999) s(i)
EXCEPT
SELECT pseudo_encrypt(i,1,999999) FROM generate_series(1,999999) s(i)

Error 91 in VBA using classes

I'm currently trying to implement a Clark & Wright Savings Heurisitc in VBA, but I'm currently facing some problem. I'm fairly new to VBA, and this error (91) keeps apearing on similar situations, which lead me to believe I'm missing some crucial knowledge. Next I present you the code:
Public Sub CWsavings()
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim aux As Integer
Dim d As Integer
Dim r As Integer
Dim Cu(200) As customer
Dim De(12) As Depot
For i = 1 To 200
Set Cu(i) = New customer
Cu(i).custID = i
Cu(i).longitude = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 2)
Cu(i).latitude = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 3)
Cu(i).lt = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 4)
Cu(i).et = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 5)
Cu(i).weekdemand = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 6)
Cu(i).peakdemand = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 7)
Cu(i).D1 = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 8)
Cu(i).D2 = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 9)
Next i
For j = 1 To 12
Set De(j) = New Depot
De(j).depotID = j
De(j).Dname = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 13)
De(j).latitude = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 14)
De(j).longitude = ThisWorkbook.Sheets("Folha1").Cells(i + 1, 15)
De(j).ncust = ThisWorkbook.Sheets("Results").Cells(j, 7)
De(j).nroute = 0
For k = 1 To De(j).ncust
aux = ThisWorkbook.Sheets("Results").Cells(j + 1, 10 + k)
Call De(j).SetCustomer(Cu(aux), k)
Next k
Next j
For d = 1 To 12
Dim M(30, 30) As Double
Dim maxsav As Double
Dim maxpos(2) As Integer
Dim connorder(676, 2) 'order of connections for routing
Dim it As Integer
it = 0
For i = 1 To De(d).ncust
For j = 1 To De(d).ncust
M(i, j) = CalcSavings(De(d), De(d).customer(i), De(d).customer(j)) ' error here
Next j
Next i
itbegin:
maxsav = 0
maxpos(1) = 0
maxpos(2) = 0
For i = 1 To De(d).ncust
For j = 1 To De(d).ncust
If i <> j Then
If M(i, j) > maxsav Then
maxsav = M(i, j)
maxpos(1) = i
maxpos(j) = j
End If
End If
Next j
Next i
it = it + 1
connorder(it, 1) = maxpos(1)
connorder(it, 2) = maxpos(2)
If it < De(d).ncust * De(d).ncust - ncust Then
M(maxpos(1), maxpos(2)) = 0
GoTo itbegin
End If
Next d
End Sub
Public Function CalcSavings(d As Depot, C1 As customer, C2 As customer)
Dim id As Double
Dim dj As Double
Dim ij As Double
id = DeptDist(C1, d)
dj = DeptDist(C2, d)
ij = CustDist(C1, C2)
CalcSavings = id + dj - ij
End Function
The class Depot:
Public depotID As Integer
Public Dname As String
Public latitude As Double
Public longitude As Double
Private customers(200) As customer
Public ncust As Integer
Private routes(500) As route
Public nroute As Integer
Public Sub addcust(C As customer)
ncust = ncust + 1
Set customers(ncust) = C
End Sub
Public Sub addroute(R As route)
nroute = Me.nroute + 1
Set routes(Me.nroute) = R
End Sub
Public Property Get customer(i As Integer) As customer
customer = customers(i)
End Property
Public Sub SetCustomer(C As customer, i As Integer)
Set customers(i) = C
End Sub
Public Property Get route(i As Integer) As route
route = routes(i)
End Property
Public Sub SetRoute(R As route, i As Integer)
Set routes(i) = R
End Sub
(Class depot Updated)
And the class Customer:
Public custID As Integer
Public latitude As Double
Public longitude As Double
Public lt As Double
Public et As Double
Public weekdemand As Integer
Public peakdemand As Integer
Public D1 As Integer
Public D2 As Integer
I'm sorry for the long post, any help would be appreciated.
Final answer...
VERY ODDLY, (not that odd, when you really look at it, but) you need to use Set even in your Get properties. I guess the reason behind this is because you're returning an object, and even though that object may already exist, you're not going to use that very object. A copy is used instead and Set becomes vital to initialize that copy.
For example, here's what your "get customer" should look like :
Public Property Get customer(i As Integer) As customer
Set customer = customers(i)
End Property
I guess it all makes sense; your array is private, and therefore you wouldn't want to pass the exact object that is contained inside that array, or it'd be counter-logic.
I think I found it... again...!
Try this :
Public Sub SetCustomer(C As customer, i As Integer)
Set customers(i) = C
End Sub
Notice customer(i) was replaced by customers(i)
EDIT : Deleted previous answer, as I was mostly fishing.

Multiply numbers after each other

Exercise Product1ToN (Loop): Write a program called Product1ToN to compute the product of integers 1 to 10 (i.e., 1×2×3×...×10). Try computing the product from 1 to 11, 1 to 12, 1 to 13 and 1 to 14. Write down the product obtained and explain the results.
How can I do this, and are their multiple ways?
Try this:
private int Product1ToN(int n){
int result = 1, ctr = 1;
while(ctr <= n){
result *= ctr++;
}
return result;
}
Hope this helps.