Skip to content

Commit 79d8a8d

Browse files
Merge branch 'main' of github.com:vlang/vsl into feature/new-lapack
* 'main' of github.com:vlang/vsl: feat: Improve machine learning models and data struct in vsl.ml feat: Add machine learning models and data struct to vsl.ml noise: add simplex noise (#207) poly: edit multiply and add divide functions (#215)
2 parents d9fd254 + 665fa11 commit 79d8a8d

File tree

15 files changed

+908
-187
lines changed

15 files changed

+908
-187
lines changed

examples/noise_fractal_2d/README.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Example - noise_fractal_2d 📘
2+
3+
This example demonstrates the usage of the V Scientific Library for generating pink noise.
4+
5+
## Instructions
6+
7+
1. Ensure you have the V compiler installed. You can download it from [here](https://vlang.io).
8+
2. Ensure you have the VSL installed. You can do it following the [installation guide](https://github.com/vlang/vsl?tab=readme-ov-file#-installation)!
9+
3. Navigate to this directory.
10+
4. Run the example using the following command:
11+
12+
```sh
13+
v run main.v
14+
```
15+
16+
Enjoy exploring the capabilities of the V Scientific Library! 😊

examples/noise_fractal_2d/main.v

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
module main
2+
3+
import rand
4+
import vsl.noise
5+
import vsl.plot
6+
7+
fn main() {
8+
// Creation of the noise generator.
9+
// Other noise functions and dimensions count are available.
10+
rand.seed([u32(3155200429), u32(3208395956)])
11+
mut generator := noise.Generator.new()
12+
generator.randomize()
13+
14+
mut x := []f64{}
15+
mut y := []f64{}
16+
mut z := []f64{}
17+
18+
// 5 layers of simplex noise
19+
octaves := 5
20+
persistence := 0.5
21+
22+
for xx in 0 .. 200 {
23+
for yy in 0 .. 200 {
24+
mut total := 0.0
25+
mut frequency := 1.0
26+
mut amplitude := 1.0
27+
mut max_value := 0.0
28+
29+
for _ in 0 .. octaves {
30+
total += generator.simplex_2d(0.03 * xx * frequency, 0.03 * yy * frequency) * amplitude
31+
max_value += amplitude
32+
amplitude *= persistence
33+
frequency *= 2.0
34+
}
35+
36+
// Normalize to [-1, 1]
37+
total /= max_value
38+
x << xx
39+
y << yy
40+
z << total
41+
}
42+
}
43+
44+
mut plt := plot.Plot.new()
45+
plt.heatmap(
46+
x: x
47+
y: y
48+
z: z
49+
)
50+
plt.layout(
51+
title: 'Pink `fractal` noise 2d example'
52+
)
53+
plt.show()!
54+
}

examples/noise_simplex_2d/README.md

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Example - noise_simple_2d 📘
2+
3+
This example demonstrates the usage of the V Scientific Library for generating simplex noise.
4+
5+
## Instructions
6+
7+
1. Ensure you have the V compiler installed. You can download it from [here](https://vlang.io).
8+
2. Ensure you have the VSL installed. You can do it following the [installation guide](https://github.com/vlang/vsl?tab=readme-ov-file#-installation)!
9+
3. Navigate to this directory.
10+
4. Run the example using the following command:
11+
12+
```sh
13+
v run main.v
14+
```
15+
16+
Enjoy exploring the capabilities of the V Scientific Library! 😊

examples/noise_simplex_2d/main.v

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module main
2+
3+
import rand
4+
import vsl.noise
5+
import vsl.plot
6+
7+
fn main() {
8+
// Creation of the noise generator.
9+
// Other noise functions and dimensions count are available.
10+
rand.seed([u32(3155200429), u32(3208395956)])
11+
mut generator := noise.Generator.new()
12+
generator.randomize()
13+
14+
mut x := []f64{}
15+
mut y := []f64{}
16+
mut z := []f64{}
17+
18+
for xx in 0 .. 40 {
19+
for yy in 0 .. 40 {
20+
// We need to scale the coordinates to control the frequency of the noise.
21+
val := generator.simplex_2d(0.03 * xx, 0.03 * yy)
22+
x << xx
23+
y << yy
24+
z << val
25+
}
26+
}
27+
28+
mut plt := plot.Plot.new()
29+
plt.heatmap(
30+
x: x
31+
y: y
32+
z: z
33+
)
34+
plt.layout(
35+
title: 'Simplex noise 2d example'
36+
)
37+
plt.show()!
38+
}

ml/README.md

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# VSL Machine Learning (vsl.ml)
2+
3+
VSL aims to provide a robust set of tools for scientific computing with an emphasis
4+
on performance and ease of use. In the `vsl.ml` module, some machine learning
5+
models are designed as observers of data, meaning they re-train automatically when
6+
data changes, while others do not require this functionality.
7+
8+
## Key Features
9+
10+
- **Observers of Data**: Some machine learning models in VSL act as observers,
11+
re-training automatically when data changes.
12+
- **High Performance**: Leverages V’s performance optimizations and can integrate
13+
with C and Fortran libraries like Open BLAS and LAPACK.
14+
- **Versatile Algorithms**: Supports a variety of machine learning algorithms and
15+
models.
16+
17+
## Usage
18+
19+
### Loading Data
20+
21+
The `Data` struct in `vsl.ml` is designed to hold data in matrix format for machine
22+
learning tasks. Here's a brief overview of how to use it:
23+
24+
#### Creating a Data Object
25+
26+
You can create a `Data` object using the following methods:
27+
28+
- `Data.new`: Creates a new `Data` object with specified dimensions.
29+
- `Data.from_raw_x`: Creates a `Data` object from raw x values (without y values).
30+
- `Data.from_raw_xy`: Creates a `Data` object from raw x and y values combined in a single matrix.
31+
- `Data.from_raw_xy_sep`: Creates a `Data` object from separate x and y raw values.
32+
33+
### Data Methods
34+
35+
The `Data` struct has several key methods to manage and manipulate data:
36+
37+
- `set(x, y)`: Sets the x matrix and y vector and notifies observers.
38+
- `set_y(y)`: Sets the y vector and notifies observers.
39+
- `set_x(x)`: Sets the x matrix and notifies observers.
40+
- `split(ratio)`: Splits the data into two parts based on the given ratio.
41+
- `clone()`: Returns a deep copy of the Data object without observers.
42+
- `clone_with_same_x()`: Returns a deep copy of the Data object but shares the same x reference.
43+
- `add_observer(obs)`: Adds an observer to the data object.
44+
- `notify_update()`: Notifies observers of data changes.
45+
46+
### Stat Observer
47+
48+
The `Stat` struct is an observer of `Data`, providing statistical analysis of the
49+
data it observes. It automatically updates its statistics when the underlying data
50+
changes.
51+
52+
## Observer Models
53+
54+
The following machine learning models in VSL are compatible with the `Observer`
55+
pattern. This means they can observe data changes and automatically update
56+
themselves.
57+
58+
### K-Means Clustering
59+
60+
K-Means Clustering is used for unsupervised learning to group data points into
61+
clusters. As an observer model, it re-trains automatically when the data changes,
62+
which is useful for dynamic datasets that require continuous updates.
63+
64+
### K-Nearest Neighbors (KNN)
65+
66+
K-Nearest Neighbors (KNN) is used for classification tasks where the target
67+
variable is categorical. As an observer model, it re-trains automatically when the
68+
data changes, which is beneficial for datasets that are frequently updated.
69+
70+
## Non-Observer Models
71+
72+
The following machine learning models in VSL do not require the observer pattern
73+
and are trained once on a dataset without continuous updates.
74+
75+
### Linear Regression
76+
77+
Linear Regression is used for predicting a continuous target variable based on one
78+
or more predictor variables. It is typically trained once on a dataset and used to
79+
make predictions without requiring continuous updates. Hence, it is not implemented
80+
as an observer model.

noise/noise.v

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
module noise
2+
3+
import rand
4+
5+
// Generator is a struct holding the permutation table used in perlin and simplex noise
6+
pub struct Generator {
7+
mut:
8+
perm []int = rand.shuffle_clone(permutations) or { panic(err) }
9+
}
10+
11+
// new is a function that return a new Generator struct
12+
pub fn Generator.new() Generator {
13+
return Generator{}
14+
}
15+
16+
// randomize is a function that shuffle the permutation set inside the Generator struct
17+
// will not shuffle if rand.seed is not changed
18+
pub fn (mut generator Generator) randomize() {
19+
generator.perm = rand.shuffle_clone(permutations) or { panic(err) }
20+
}

noise/perlin2d.v

+7-26
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,7 @@
11
module noise
22

3-
import rand
4-
5-
// Perlin is a struct that hold the permutation set for perlin noise
6-
pub struct Perlin {
7-
mut:
8-
perm []int = rand.shuffle_clone(permutations) or { panic(err) }
9-
}
10-
11-
// new is a function that return a new Perlin struct
12-
pub fn Perlin.new() Perlin {
13-
return Perlin{}
14-
}
15-
16-
// randomize is a function that shuffle the permutation set inside the Perlin struct
17-
// will not shuffle if rand.seed is not changed
18-
pub fn (mut perlin Perlin) randomize() {
19-
perlin.perm = rand.shuffle_clone(permutations) or { panic(err) }
20-
}
21-
223
// perlin2d is a function that return a single value of perlin noise for a given 2d position
23-
pub fn (perlin Perlin) perlin2d(x f64, y f64) f64 {
4+
pub fn (generator Generator) perlin2d(x f64, y f64) f64 {
245
xi := int(x) & 0xFF
256
yi := int(y) & 0xFF
267

@@ -30,13 +11,13 @@ pub fn (perlin Perlin) perlin2d(x f64, y f64) f64 {
3011
u := fade(xf)
3112
v := fade(yf)
3213

33-
pxi := perlin.perm[xi]
34-
pxi1 := perlin.perm[xi + 1]
14+
pxi := generator.perm[xi]
15+
pxi1 := generator.perm[xi + 1]
3516

36-
aa := perlin.perm[pxi + yi]
37-
ab := perlin.perm[pxi + yi + 1]
38-
ba := perlin.perm[pxi1 + yi]
39-
bb := perlin.perm[pxi1 + yi + 1]
17+
aa := generator.perm[pxi + yi]
18+
ab := generator.perm[pxi + yi + 1]
19+
ba := generator.perm[pxi1 + yi]
20+
bb := generator.perm[pxi1 + yi + 1]
4021

4122
x1 := lerp(grad2d(aa, xf, yf), grad2d(ba, xf - 1, yf), u)
4223
x2 := lerp(grad2d(ab, xf, yf - 1), grad2d(bb, xf - 1, yf - 1), u)

noise/perlin2d_test.v

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import vsl.float.float64
66
fn test_perlin2d() {
77
rand.seed([u32(3155200429), u32(3208395956)])
88

9-
mut gen := Perlin.new()
9+
mut gen := Generator.new()
1010
gen.randomize()
1111

1212
result := gen.perlin2d(0.125, 0.125)

noise/perlin3d.v

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
module noise
22

33
// perlin3d is a function that return a single value of perlin noise for a given 3d position
4-
pub fn (perlin Perlin) perlin3d(x f64, y f64, z f64) f64 {
4+
pub fn (generator Generator) perlin3d(x f64, y f64, z f64) f64 {
55
xi := int(x) & 0xFF
66
yi := int(y) & 0xFF
77
zi := int(z) & 0xFF
@@ -12,21 +12,21 @@ pub fn (perlin Perlin) perlin3d(x f64, y f64, z f64) f64 {
1212
v := fade(yf)
1313
w := fade(zf)
1414

15-
pxi := perlin.perm[xi]
16-
pxi_yi := perlin.perm[pxi + yi]
17-
pxi_yi1 := perlin.perm[pxi + yi + 1]
18-
pxi1 := perlin.perm[xi + 1]
19-
pxi1_yi := perlin.perm[pxi1 + yi]
20-
pxi1_yi1 := perlin.perm[pxi1 + yi + 1]
15+
pxi := generator.perm[xi]
16+
pxi_yi := generator.perm[pxi + yi]
17+
pxi_yi1 := generator.perm[pxi + yi + 1]
18+
pxi1 := generator.perm[xi + 1]
19+
pxi1_yi := generator.perm[pxi1 + yi]
20+
pxi1_yi1 := generator.perm[pxi1 + yi + 1]
2121

22-
aaa := perlin.perm[pxi_yi + zi]
23-
aba := perlin.perm[pxi_yi1 + zi]
24-
aab := perlin.perm[pxi_yi + zi + 1]
25-
abb := perlin.perm[pxi_yi1 + zi + 1]
26-
baa := perlin.perm[pxi1_yi + zi]
27-
bba := perlin.perm[pxi1_yi1 + zi]
28-
bab := perlin.perm[pxi1_yi + zi + 1]
29-
bbb := perlin.perm[pxi1_yi1 + zi + 1]
22+
aaa := generator.perm[pxi_yi + zi]
23+
aba := generator.perm[pxi_yi1 + zi]
24+
aab := generator.perm[pxi_yi + zi + 1]
25+
abb := generator.perm[pxi_yi1 + zi + 1]
26+
baa := generator.perm[pxi1_yi + zi]
27+
bba := generator.perm[pxi1_yi1 + zi]
28+
bab := generator.perm[pxi1_yi + zi + 1]
29+
bbb := generator.perm[pxi1_yi1 + zi + 1]
3030

3131
mut x1 := lerp(grad3d(aaa, xf, yf, zf), grad3d(baa, xf - 1, yf, zf), u)
3232
mut x2 := lerp(grad3d(aba, xf, yf - 1, zf), grad3d(bba, xf - 1, yf - 1, zf), u)

noise/perlin3d_test.v

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import vsl.float.float64
66
fn test_perlin3d() {
77
rand.seed([u32(3155200429), u32(3208395956)])
88

9-
mut gen := Perlin.new()
9+
mut gen := Generator.new()
1010
gen.randomize()
1111

1212
result := gen.perlin3d(0.125, 0.125, 0.125)

0 commit comments

Comments
 (0)