Skip to content

Commit 4a7301b

Browse files
committed
LRPS Algorithm v.1.0.0
Logarithmic Random Ponderated Selector; recieves a list of elements and throw randomly one of them, but the closer the element is to the start of the list is more probability to get these element on the random selection, based on the logarithmic/exponential curve form
0 parents  commit 4a7301b

File tree

5 files changed

+185
-0
lines changed

5 files changed

+185
-0
lines changed

Algorithm/experiments.py

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import matplotlib.pyplot as plt
2+
from logrps import logrps
3+
4+
#* It counts and verifies the bias on the selections,
5+
#* repeating the selection experiment a lot of times:
6+
times = int(input("\nRepetitions: "))
7+
8+
#? Example list of 10 elements;
9+
#* The algorithm has to recieve this list and select randomly one element;
10+
#* By repeating the selection a lot of times, the result has to be that the
11+
#* first element "E1" is the most frecuent selected, and then "E2", etc.
12+
#! IF YOU WANT TO MAKE SOME EXPERIMENTS WITH AN OWN IDEA OF SELECTION LIST
13+
#! YOU JUST HAVE TO PUT INTO THE LIST "elements" WHATEVER YOU WANT!
14+
elements: list = ["E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "E10"]
15+
counter = []
16+
n = len(elements)
17+
18+
#? Fills a counter vector with 0's; it will contains the amount of times that
19+
#? each element of the list was selected:
20+
for i in range(0, n):
21+
counter.append(0)
22+
23+
#/ Does all the repetitions of the experiment using the logrps function to select
24+
#/ something on the list; and counts the times that each element was selected.
25+
for _ in range(0, times):
26+
selected = logrps(elements)
27+
index = elements.index(selected)
28+
counter[index] += 1
29+
30+
#? Prints the data from the counter:
31+
print(f"Elements on list: {n}")
32+
print("\nSelected times:")
33+
for i in range(0, n):
34+
print(f"Element #{i+1} [{elements[i]}]: {counter[i]} times selected;")
35+
36+
37+
# Draws the line in a graph:
38+
plt.rcParams["figure.figsize"] = [10, 5]
39+
plt.rcParams["figure.autolayout"] = True
40+
41+
# Points with:
42+
# (element, amountOfSelections ):
43+
# points: list = []
44+
x_values: list = []
45+
y_values: list = []
46+
47+
# Put all the points:
48+
for i in range(0, n):
49+
# points.append([i+1, counter[i]])
50+
x_values.append(i+1)
51+
y_values.append(counter[i])
52+
53+
# Shows the graphic:
54+
plt.title("LOGARITHMIC RANDOM PONDERATED SELECTOR")
55+
plt.ylabel("Amount of selected times")
56+
plt.xlabel("Number of element")
57+
info = f"For {n} elements;\nWith {times} choices;"
58+
plt.annotate(info,
59+
xy=(0.96, 0.8), xytext=(0, 12),
60+
xycoords=("axes fraction", "figure fraction"),
61+
textcoords="offset points",
62+
size=10, ha="right", va="top",
63+
bbox=dict(boxstyle="square,pad=1.0", fc="white", ec="b", lw=2))
64+
65+
plt.plot(x_values, y_values, "bo", linestyle="-")
66+
plt.savefig("logselection.png", dpi="figure")
67+
plt.show()
68+
print()

Algorithm/logrps.py

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
'''
2+
Logarithmic Random Poderated Selector Algorithm
3+
'''
4+
5+
import random
6+
import math
7+
8+
def logrps(elements: list):
9+
10+
'''
11+
Logarithmic Random Poderated Selector:
12+
13+
This algorithm gets a list of elements, and using
14+
a logarithmic scale, selects randomly one member
15+
of the list giving a higher probability weight to
16+
the initial elements of the list.
17+
18+
This algorithm selects with more frecuency the
19+
initial members of the list, based on the
20+
logarithmic/exponential curve form.
21+
'''
22+
23+
#* Amount of elements: "n":
24+
n = len(elements)
25+
26+
#* Validation cases:
27+
#? When list is empty:
28+
if n == 0:
29+
return "List cannot be empty :c"
30+
#? When list has only one element:
31+
if n == 1:
32+
return elements[0]
33+
34+
#* Throws a random float number based on the n elements:
35+
#? To operate the numbers, it will consider 1 as the
36+
#? first element; then when it selects an index of the
37+
#? list, it will take at 0-starting notation:
38+
#/ Random float between 1 and n with 4 decimals.
39+
#* This random represent a random point of selection
40+
#* in a linear axis in which all elements has the same
41+
#* space to be selected:
42+
randomLinearPoint = round(random.uniform(0, n), 4)
43+
# print(f"\nRandom Lineal Point: {randomLinearPoint}; ", end="")
44+
45+
'''
46+
This is the propuse:
47+
48+
* Having a linear scale between 1 - n, all the spaces
49+
between elements has the same size.
50+
51+
* Having a logarithmic scale between 1 - n, the spaces
52+
between elements are different; the first element has
53+
the biggest space, the second is smaller, etc. The
54+
differences between the spaces is based on logarithms.
55+
56+
* When the random is selected, you get the linear scale
57+
element; then it has to ponderate the space with the
58+
logarithmic scale, to select the equivalent.
59+
60+
Example:
61+
NOTE: E1, E2, ..., E6 are the 6 elements of the list.
62+
63+
LINEAR SCALE:
64+
E1 E2 E3 E4 E5 E6
65+
0 1 2 3 4 5 6
66+
|-------|-------|-------|-------|-------|-------|
67+
68+
RANDOM POINT:
69+
*
70+
71+
LOGARITHMIC SCALE:
72+
E1 E2 E3 E4 E5 E6
73+
0 1 2 3 4 5 6
74+
|----------------|-----------|-------|----|---|-|
75+
76+
SELECTION:
77+
78+
* Linear: 3.24: [E4];
79+
* Logarithmic: 3: [E2];
80+
81+
'''
82+
83+
#? The formula to calculate the distance between the start of
84+
#? the scale, and an "i" logarithmic point, is:
85+
#/ logPoint = n*log_n+1(i+1);
86+
#* So, it starts a loop to check if the random linear point is
87+
#* between the space of the first log point, or the second, or
88+
#* the third, etc.
89+
for i in range(2, (n+1)+1):
90+
# print((n+1) * math.log(i, n+1), end=" ")
91+
if randomLinearPoint <= (n * math.log(i, n+1)):
92+
#! Returns the selected element:
93+
# print(f"Logarithmic point: {i-1};")
94+
return elements[(i-1)-1]

Algorithm/logselection.png

36 KB
Loading

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Alejandro Ramos
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# LRPS-Algorithm
2+
⚖ Own proposal of Selection Method Algorithm: Logarithmic Random Ponderated Selector; throw a random element of a list; but the closer the element is to the start is more probability to appear, based on logarithmic/exponential scale.

0 commit comments

Comments
 (0)