Skip to content

Commit 6f61c63

Browse files
committed
Improve DSL
Relate-To: #94, #119
1 parent cb6a4cb commit 6f61c63

5 files changed

Lines changed: 631 additions & 14 deletions

File tree

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package sk.ainet.core.tensor
2+
3+
import kotlin.random.Random
4+
5+
public interface TensorFactory<T: DType, V> {
6+
public fun zeros(shape: Shape): Tensor<T, V>
7+
public fun ones(shape: Shape): Tensor<T, V>
8+
public fun random(shape: Shape): Tensor<T, V>
9+
10+
// Advanced random methods with seed control
11+
public fun random(shape: Shape, seed: Long): Tensor<T, V>
12+
public fun random(shape: Shape, random: Random): Tensor<T, V>
13+
14+
// Distribution-based random methods
15+
public fun randomNormal(shape: Shape, mean: Double = 0.0, std: Double = 1.0): Tensor<T, V>
16+
public fun randomNormal(shape: Shape, mean: Double = 0.0, std: Double = 1.0, seed: Long): Tensor<T, V>
17+
public fun randomNormal(shape: Shape, mean: Double = 0.0, std: Double = 1.0, random: Random): Tensor<T, V>
18+
19+
public fun randomUniform(shape: Shape, min: Double = 0.0, max: Double = 1.0): Tensor<T, V>
20+
public fun randomUniform(shape: Shape, min: Double = 0.0, max: Double = 1.0, seed: Long): Tensor<T, V>
21+
public fun randomUniform(shape: Shape, min: Double = 0.0, max: Double = 1.0, random: Random): Tensor<T, V>
22+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package sk.ainet.core.tensor
2+
3+
/**
4+
* Provides default TensorFactory instances for supported DType and value type combinations.
5+
* This enables automatic factory resolution in DSL contexts without requiring explicit factory parameters.
6+
*
7+
* The implementation uses type-based resolution to return the appropriate backend factory.
8+
*/
9+
public object DefaultTensorFactories {
10+
11+
/**
12+
* Internal storage for factory instances to avoid recreating them.
13+
*/
14+
private var fp32Factory: TensorFactory<FP32, Float>? = null
15+
private var int8Factory: TensorFactory<Int8, Byte>? = null
16+
private var int32Factory: TensorFactory<Int32, Int>? = null
17+
18+
/**
19+
* Sets the FP32 factory implementation. This is called by the implementation module.
20+
*/
21+
public fun setFP32Factory(factory: TensorFactory<FP32, Float>) {
22+
fp32Factory = factory
23+
}
24+
25+
/**
26+
* Sets the Int8 factory implementation. This is called by the implementation module.
27+
*/
28+
public fun setInt8Factory(factory: TensorFactory<Int8, Byte>) {
29+
int8Factory = factory
30+
}
31+
32+
/**
33+
* Sets the Int32 factory implementation. This is called by the implementation module.
34+
*/
35+
public fun setInt32Factory(factory: TensorFactory<Int32, Int>) {
36+
int32Factory = factory
37+
}
38+
39+
/**
40+
* Gets the default TensorFactory for FP32/Float combinations.
41+
*/
42+
public fun getFP32Factory(): TensorFactory<FP32, Float> {
43+
return fp32Factory ?: throw IllegalStateException(
44+
"FP32 factory not initialized. Make sure the tensor implementation module is included."
45+
)
46+
}
47+
48+
/**
49+
* Gets the default TensorFactory for Int8/Byte combinations.
50+
*/
51+
public fun getInt8Factory(): TensorFactory<Int8, Byte> {
52+
return int8Factory ?: throw IllegalStateException(
53+
"Int8 factory not initialized. Make sure the tensor implementation module is included."
54+
)
55+
}
56+
57+
/**
58+
* Gets the default TensorFactory for Int32/Int combinations.
59+
*/
60+
public fun getInt32Factory(): TensorFactory<Int32, Int> {
61+
return int32Factory ?: throw IllegalStateException(
62+
"Int32 factory not initialized. Make sure the tensor implementation module is included."
63+
)
64+
}
65+
}

skainet-core/skainet-tensors/src/commonMain/kotlin/sk/ainet/core/tensor/backend/CpuBackend.kt

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,6 +1336,67 @@ public class CpuBackend : ComputeBackend<FP32, Float> {
13361336
override fun ones(shape: Shape): Tensor<FP32, Float> {
13371337
return CpuTensorFP32.ones(shape)
13381338
}
1339+
1340+
override fun random(shape: Shape): Tensor<FP32, Float> {
1341+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) { kotlin.random.Random.nextFloat() })
1342+
}
1343+
1344+
override fun random(shape: Shape, seed: Long): Tensor<FP32, Float> {
1345+
val random = kotlin.random.Random(seed)
1346+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) { random.nextFloat() })
1347+
}
1348+
1349+
override fun random(shape: Shape, random: kotlin.random.Random): Tensor<FP32, Float> {
1350+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) { random.nextFloat() })
1351+
}
1352+
1353+
override fun randomNormal(shape: Shape, mean: Double, std: Double): Tensor<FP32, Float> {
1354+
val random = kotlin.random.Random
1355+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) {
1356+
(generateNormalDistribution(random, mean, std)).toFloat()
1357+
})
1358+
}
1359+
1360+
override fun randomNormal(shape: Shape, mean: Double, std: Double, seed: Long): Tensor<FP32, Float> {
1361+
val random = kotlin.random.Random(seed)
1362+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) {
1363+
(generateNormalDistribution(random, mean, std)).toFloat()
1364+
})
1365+
}
1366+
1367+
override fun randomNormal(shape: Shape, mean: Double, std: Double, random: kotlin.random.Random): Tensor<FP32, Float> {
1368+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) {
1369+
(generateNormalDistribution(random, mean, std)).toFloat()
1370+
})
1371+
}
1372+
1373+
override fun randomUniform(shape: Shape, min: Double, max: Double): Tensor<FP32, Float> {
1374+
val random = kotlin.random.Random
1375+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) {
1376+
(random.nextDouble(min, max)).toFloat()
1377+
})
1378+
}
1379+
1380+
override fun randomUniform(shape: Shape, min: Double, max: Double, seed: Long): Tensor<FP32, Float> {
1381+
val random = kotlin.random.Random(seed)
1382+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) {
1383+
(random.nextDouble(min, max)).toFloat()
1384+
})
1385+
}
1386+
1387+
override fun randomUniform(shape: Shape, min: Double, max: Double, random: kotlin.random.Random): Tensor<FP32, Float> {
1388+
return CpuTensorFP32.fromArray(shape, FloatArray(shape.volume) {
1389+
(random.nextDouble(min, max)).toFloat()
1390+
})
1391+
}
1392+
1393+
private fun generateNormalDistribution(random: kotlin.random.Random, mean: Double, std: Double): Double {
1394+
// Box-Muller transform for generating normal distribution
1395+
val u1 = random.nextDouble()
1396+
val u2 = random.nextDouble()
1397+
val z0 = sqrt(-2.0 * ln(u1)) * cos(2.0 * PI * u2)
1398+
return z0 * std + mean
1399+
}
13391400
}
13401401

13411402
/**
@@ -1446,6 +1507,64 @@ public class CpuBackendInt8 : ComputeBackend<Int8, Byte> {
14461507

14471508
override fun ones(shape: Shape): Tensor<Int8, Byte> =
14481509
CpuTensorInt8.ones(shape)
1510+
1511+
override fun random(shape: Shape): Tensor<Int8, Byte> =
1512+
CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) { kotlin.random.Random.nextInt(-128, 128).toByte() })
1513+
1514+
override fun random(shape: Shape, seed: Long): Tensor<Int8, Byte> {
1515+
val random = kotlin.random.Random(seed)
1516+
return CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) { random.nextInt(-128, 128).toByte() })
1517+
}
1518+
1519+
override fun random(shape: Shape, random: kotlin.random.Random): Tensor<Int8, Byte> =
1520+
CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) { random.nextInt(-128, 128).toByte() })
1521+
1522+
override fun randomNormal(shape: Shape, mean: Double, std: Double): Tensor<Int8, Byte> {
1523+
val random = kotlin.random.Random
1524+
return CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) {
1525+
generateNormalDistributionInt8(random, mean, std)
1526+
})
1527+
}
1528+
1529+
override fun randomNormal(shape: Shape, mean: Double, std: Double, seed: Long): Tensor<Int8, Byte> {
1530+
val random = kotlin.random.Random(seed)
1531+
return CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) {
1532+
generateNormalDistributionInt8(random, mean, std)
1533+
})
1534+
}
1535+
1536+
override fun randomNormal(shape: Shape, mean: Double, std: Double, random: kotlin.random.Random): Tensor<Int8, Byte> =
1537+
CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) {
1538+
generateNormalDistributionInt8(random, mean, std)
1539+
})
1540+
1541+
override fun randomUniform(shape: Shape, min: Double, max: Double): Tensor<Int8, Byte> {
1542+
val random = kotlin.random.Random
1543+
return CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) {
1544+
random.nextInt(min.toInt().coerceAtLeast(-128), max.toInt().coerceAtMost(127) + 1).toByte()
1545+
})
1546+
}
1547+
1548+
override fun randomUniform(shape: Shape, min: Double, max: Double, seed: Long): Tensor<Int8, Byte> {
1549+
val random = kotlin.random.Random(seed)
1550+
return CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) {
1551+
random.nextInt(min.toInt().coerceAtLeast(-128), max.toInt().coerceAtMost(127) + 1).toByte()
1552+
})
1553+
}
1554+
1555+
override fun randomUniform(shape: Shape, min: Double, max: Double, random: kotlin.random.Random): Tensor<Int8, Byte> =
1556+
CpuTensorInt8.fromArray(shape, ByteArray(shape.volume) {
1557+
random.nextInt(min.toInt().coerceAtLeast(-128), max.toInt().coerceAtMost(127) + 1).toByte()
1558+
})
1559+
1560+
private fun generateNormalDistributionInt8(random: kotlin.random.Random, mean: Double, std: Double): Byte {
1561+
// Box-Muller transform for generating normal distribution
1562+
val u1 = random.nextDouble()
1563+
val u2 = random.nextDouble()
1564+
val z0 = sqrt(-2.0 * ln(u1)) * cos(2.0 * PI * u2)
1565+
val value = (z0 * std + mean).toInt().coerceIn(-128, 127)
1566+
return value.toByte()
1567+
}
14491568
}
14501569

14511570
/**
@@ -1554,4 +1673,61 @@ public class CpuBackendInt32 : ComputeBackend<Int32, Int> {
15541673

15551674
override fun ones(shape: Shape): Tensor<Int32, Int> =
15561675
CpuTensorInt32.ones(shape)
1676+
1677+
override fun random(shape: Shape): Tensor<Int32, Int> =
1678+
CpuTensorInt32.fromArray(shape, IntArray(shape.volume) { kotlin.random.Random.nextInt() })
1679+
1680+
override fun random(shape: Shape, seed: Long): Tensor<Int32, Int> {
1681+
val random = kotlin.random.Random(seed)
1682+
return CpuTensorInt32.fromArray(shape, IntArray(shape.volume) { random.nextInt() })
1683+
}
1684+
1685+
override fun random(shape: Shape, random: kotlin.random.Random): Tensor<Int32, Int> =
1686+
CpuTensorInt32.fromArray(shape, IntArray(shape.volume) { random.nextInt() })
1687+
1688+
override fun randomNormal(shape: Shape, mean: Double, std: Double): Tensor<Int32, Int> {
1689+
val random = kotlin.random.Random
1690+
return CpuTensorInt32.fromArray(shape, IntArray(shape.volume) {
1691+
generateNormalDistributionInt32(random, mean, std)
1692+
})
1693+
}
1694+
1695+
override fun randomNormal(shape: Shape, mean: Double, std: Double, seed: Long): Tensor<Int32, Int> {
1696+
val random = kotlin.random.Random(seed)
1697+
return CpuTensorInt32.fromArray(shape, IntArray(shape.volume) {
1698+
generateNormalDistributionInt32(random, mean, std)
1699+
})
1700+
}
1701+
1702+
override fun randomNormal(shape: Shape, mean: Double, std: Double, random: kotlin.random.Random): Tensor<Int32, Int> =
1703+
CpuTensorInt32.fromArray(shape, IntArray(shape.volume) {
1704+
generateNormalDistributionInt32(random, mean, std)
1705+
})
1706+
1707+
override fun randomUniform(shape: Shape, min: Double, max: Double): Tensor<Int32, Int> {
1708+
val random = kotlin.random.Random
1709+
return CpuTensorInt32.fromArray(shape, IntArray(shape.volume) {
1710+
random.nextInt(min.toInt(), max.toInt() + 1)
1711+
})
1712+
}
1713+
1714+
override fun randomUniform(shape: Shape, min: Double, max: Double, seed: Long): Tensor<Int32, Int> {
1715+
val random = kotlin.random.Random(seed)
1716+
return CpuTensorInt32.fromArray(shape, IntArray(shape.volume) {
1717+
random.nextInt(min.toInt(), max.toInt() + 1)
1718+
})
1719+
}
1720+
1721+
override fun randomUniform(shape: Shape, min: Double, max: Double, random: kotlin.random.Random): Tensor<Int32, Int> =
1722+
CpuTensorInt32.fromArray(shape, IntArray(shape.volume) {
1723+
random.nextInt(min.toInt(), max.toInt() + 1)
1724+
})
1725+
1726+
private fun generateNormalDistributionInt32(random: kotlin.random.Random, mean: Double, std: Double): Int {
1727+
// Box-Muller transform for generating normal distribution
1728+
val u1 = random.nextDouble()
1729+
val u2 = random.nextDouble()
1730+
val z0 = sqrt(-2.0 * ln(u1)) * cos(2.0 * PI * u2)
1731+
return (z0 * std + mean).toInt()
1732+
}
15571733
}

0 commit comments

Comments
 (0)