Stole
Stole
MModular
Created by Pièrre on 12/25/2023 in #questions
any Windows + Vscode (using WSL2 as middle-man) guide?
Yep, I've been using it just like that for a while now and it's been working great
4 replies
MModular
Created by Vijay Yadav on 12/19/2023 in #questions
How to convert string to float value?
There is also the option of using external_call and the strtof C function, like so
let s: String = "1.48e2"
let f: Float32 = external_call["strtof", Float32, DTypePointer[DType.int8], Pointer[Int8]](s._as_ptr(), Pointer[Int8].get_null())
s._strref_keepalive()
let s: String = "1.48e2"
let f: Float32 = external_call["strtof", Float32, DTypePointer[DType.int8], Pointer[Int8]](s._as_ptr(), Pointer[Int8].get_null())
s._strref_keepalive()
Although of course the obligatory "current FFI is not stable and expect it to change" disclosure must be included
12 replies
MModular
Created by chebu_pizza on 12/13/2023 in #questions
Is it possible to push mojo code on GitHub?
Best thing to do is probably just to get them into the language itself so people naturally start using it more and pushing more Mojo files, not to tell them to create arbitrary files. It's true, we don't want to game the system
16 replies
MModular
Created by isack on 12/14/2023 in #questions
Can anyone help me to solve this error.
I think you can go ahead and still make an issue, but make it instead about a better error in this case. Because something like:
fn add(a: Int) -> Int:
return a + 1

fn main():
print(a(Int))
fn add(a: Int) -> Int:
return a + 1

fn main():
print(a(Int))
should probably produce an error less cryptic
10 replies
MModular
Created by isack on 12/14/2023 in #questions
Can anyone help me to solve this error.
I guess it's true the compiler should emit a better error than this, but changing that last Float64 to something like 0.5 (I don't know the actual base GFLOPS that Python runs this at) works
10 replies
MModular
Created by isack on 12/14/2023 in #questions
Can anyone help me to solve this error.
The reason is because you're passing the type Float64 into bench at the end, when it really expects something of the type Float64, like 1.0 or a variable
10 replies
MModular
Created by isack on 12/14/2023 in #questions
Can anyone help me to solve this error.
Wait, I completely missed something
10 replies
MModular
Created by isack on 12/14/2023 in #questions
Can anyone help me to solve this error.
Wow, this is a bad bug. Looks like an actual language one, there's something bad happening under the hood. So far I can't see a way to get around it, would be good to create an issue on the Github https://github.com/modularml/mojo/issues. I took a look and didn't see anything similar to this previously reported.
10 replies
MModular
Created by isack on 12/14/2023 in #questions
Can anyone help me to solve this error.
It looks like a double free, you're calling A.data.free() and etc. for all the matrices after the benchmark is run, but when they get destructed, each __del__ gets called, freeing the pointers again. You can keep the matrices alive a different way, like I just changed those A.data.free() calls to _ = A.rows or quite literally anything that uses the matrices, or remove the free call in __del__. I think the first option is "better" practice for now. This is what I ran, and it appears to work as expected.
from random import rand
from memory import memset, memset_zero
from memory.unsafe import DTypePointer, Pointer
import benchmark

alias type=DType.float64

struct Matrix:
var data: DTypePointer[type]
var rows: Int
var cols: Int

#initisalize zeroing all values
fn __init__(inout self, rows: Int, cols: Int):
self.data = DTypePointer[type].alloc(rows * cols)
memset_zero(self.data, rows*cols)
self.rows = rows
self.cols = cols

#initialize taking a pointer, don't set any elements
fn __init__(inout self, rows: Int, cols: Int , data: DTypePointer[DType.float64]):
self.data=data
self.cols=cols
self.rows=rows

#Initialize with random values

@staticmethod
fn rand(rows: Int, cols: Int)-> Self:
let data = DTypePointer[type].alloc(rows * cols)
rand(data, rows*cols)
return Self(rows, cols, data)

fn __getitem__(self, y: Int, x: Int)->Float64:
return self.load[1](y, x)

fn __setitem__(self, y: Int, x: Int, val: Float64):
return self.store[1](y, x, val)

fn load[nelts: Int](self, y: Int, x: Int) -> SIMD[DType.float64, nelts]:
return self.data.simd_load[nelts](y * self.cols + x)

fn store[nelts: Int](self, y: Int, x: Int, val: SIMD[DType.float64, nelts]):
return self.data.simd_store[nelts](y * self.cols + x, val)

fn __del__(owned self):
self.data.free()


fn print(self):
print_no_newline("[")
for i in range(self.rows*self.cols):
if i > 0:
print_no_newline(", ")
print_no_newline(self.data.load(i))
print("]")

# Note that C, A, and B have types.
fn matmul_naive(C: Matrix, A: Matrix, B: Matrix):
for m in range(C.rows):
for k in range(A.cols):
for n in range(C.cols):
C[m, n] += A[m, k] * B[k, n]



fn main():
alias M = 1024
alias N = 1024
alias K = 1024

@always_inline
fn bench[
func: fn (Matrix, Matrix, Matrix) -> None](base_gflops: Float64):
var C = Matrix(M, N)
var A = Matrix.rand(M, K)
var B = Matrix.rand(K, N)

@always_inline
@parameter
fn test_fn():
_ = func(C, A, B)

let secs = benchmark.run[test_fn](max_runtime_secs=1).mean()
# Prevent the matrices from being freed before the benchmark run
_ = A.rows
_ = B.rows
_ = C.rows
let gflops = ((2 * M * N * K) / secs) / 1e9
#let speedup: Float64 = gflops / base_gflops
print(gflops, "GFLOP/s")
#print(gflops, "GFLOP/s, a", speedup, "x speedup over Python")

bench[matmul_naive](Float64)
from random import rand
from memory import memset, memset_zero
from memory.unsafe import DTypePointer, Pointer
import benchmark

alias type=DType.float64

struct Matrix:
var data: DTypePointer[type]
var rows: Int
var cols: Int

#initisalize zeroing all values
fn __init__(inout self, rows: Int, cols: Int):
self.data = DTypePointer[type].alloc(rows * cols)
memset_zero(self.data, rows*cols)
self.rows = rows
self.cols = cols

#initialize taking a pointer, don't set any elements
fn __init__(inout self, rows: Int, cols: Int , data: DTypePointer[DType.float64]):
self.data=data
self.cols=cols
self.rows=rows

#Initialize with random values

@staticmethod
fn rand(rows: Int, cols: Int)-> Self:
let data = DTypePointer[type].alloc(rows * cols)
rand(data, rows*cols)
return Self(rows, cols, data)

fn __getitem__(self, y: Int, x: Int)->Float64:
return self.load[1](y, x)

fn __setitem__(self, y: Int, x: Int, val: Float64):
return self.store[1](y, x, val)

fn load[nelts: Int](self, y: Int, x: Int) -> SIMD[DType.float64, nelts]:
return self.data.simd_load[nelts](y * self.cols + x)

fn store[nelts: Int](self, y: Int, x: Int, val: SIMD[DType.float64, nelts]):
return self.data.simd_store[nelts](y * self.cols + x, val)

fn __del__(owned self):
self.data.free()


fn print(self):
print_no_newline("[")
for i in range(self.rows*self.cols):
if i > 0:
print_no_newline(", ")
print_no_newline(self.data.load(i))
print("]")

# Note that C, A, and B have types.
fn matmul_naive(C: Matrix, A: Matrix, B: Matrix):
for m in range(C.rows):
for k in range(A.cols):
for n in range(C.cols):
C[m, n] += A[m, k] * B[k, n]



fn main():
alias M = 1024
alias N = 1024
alias K = 1024

@always_inline
fn bench[
func: fn (Matrix, Matrix, Matrix) -> None](base_gflops: Float64):
var C = Matrix(M, N)
var A = Matrix.rand(M, K)
var B = Matrix.rand(K, N)

@always_inline
@parameter
fn test_fn():
_ = func(C, A, B)

let secs = benchmark.run[test_fn](max_runtime_secs=1).mean()
# Prevent the matrices from being freed before the benchmark run
_ = A.rows
_ = B.rows
_ = C.rows
let gflops = ((2 * M * N * K) / secs) / 1e9
#let speedup: Float64 = gflops / base_gflops
print(gflops, "GFLOP/s")
#print(gflops, "GFLOP/s, a", speedup, "x speedup over Python")

bench[matmul_naive](Float64)
10 replies
MModular
Created by chebu_pizza on 12/13/2023 in #questions
Is it possible to push mojo code on GitHub?
Yeah, the comment here https://github.com/github-linguist/linguist/pull/6400#issuecomment-1716773725 suggests they're separate for purposes of Linguist recognition, but maybe once both meet the requirements something different could happen. Unfortunately, I don't know too many details
16 replies
MModular
Created by chebu_pizza on 12/13/2023 in #questions
Is it possible to push mojo code on GitHub?
Yes, you can, and please do. There's a goal of 2k unique Mojo files on Github, and then they'll add Mojo as a recognized language
16 replies
MModular
Created by JIMC on 12/4/2023 in #questions
Trying to do compile time checking with 'const' type arguments.
It seems to produce the same errors on the most recent, 0.6.0 (d55c0025)
11 replies
MModular
Created by JIMC on 12/4/2023 in #questions
Trying to do compile time checking with 'const' type arguments.
As the error message suggests, it does look like due to the definition of ListLiteral that Secret or whatever is being carried has to be register passable, so I went ahead and changed the Secret struct. This might be wildly contrary to what you initially wanted, but it does look like in order to use a heterogenous collection, the types have to be register passable: including ListLiteral and Tuple. You can see (along with my great variable naming here) that the following code does not compile:
struct ExposedSecret[T: AnyRegType]:
var borrowed_value: T

fn __init__(inout self, borrowed borrowed_value: T):
self.borrowed_value = borrowed_value

@register_passable("trivial")
struct Secret[T: AnyRegType, MEC: Int, EC: Int = 0]:
var inner: T

fn __init__(owned value: T) -> Self:
return Self{inner: value}

@staticmethod
fn ec_add_one(owned other: Self) -> Secret[T, MEC, EC + 1]:
return Secret[T, MEC, EC + 1]{inner: other.inner}

fn expose_secret[ReturnedType: AnyRegType](owned self, owned closure:
fn(exposed_secret: ExposedSecret[T]) capturing -> ReturnedType)
-> ListLiteral[ReturnedType, Secret[T, MEC, EC + 1]]:
constrained[EC < MEC, "`expose_secret` can only be called if `EC < MEC`"]()
let returned_value = closure(ExposedSecret[T](self.inner))
let new_self = Secret.ec_add_one(self^)
return [returned_value, new_self]

fn main():
alias orig = Secret[Int, 3](69)
let oomy_secret = Secret.ec_add_one(orig)
let omy_secret = Secret.ec_add_one(oomy_secret)
let my_secret = Secret.ec_add_one(omy_secret)

@parameter
fn capturing_closure_but_actually_never_capture(borrowed exposed_secret: ExposedSecret[Int]) -> Int:
return exposed_secret.borrowed_value

let my_69_secret_tuple = my_secret.expose_secret[Int](capturing_closure_but_actually_never_capture)
let returned_69_secret = my_69_secret_tuple.get[0, Int]()
let my_new_secret = my_69_secret_tuple.get[1, Secret[Int, 3, 3]]()
struct ExposedSecret[T: AnyRegType]:
var borrowed_value: T

fn __init__(inout self, borrowed borrowed_value: T):
self.borrowed_value = borrowed_value

@register_passable("trivial")
struct Secret[T: AnyRegType, MEC: Int, EC: Int = 0]:
var inner: T

fn __init__(owned value: T) -> Self:
return Self{inner: value}

@staticmethod
fn ec_add_one(owned other: Self) -> Secret[T, MEC, EC + 1]:
return Secret[T, MEC, EC + 1]{inner: other.inner}

fn expose_secret[ReturnedType: AnyRegType](owned self, owned closure:
fn(exposed_secret: ExposedSecret[T]) capturing -> ReturnedType)
-> ListLiteral[ReturnedType, Secret[T, MEC, EC + 1]]:
constrained[EC < MEC, "`expose_secret` can only be called if `EC < MEC`"]()
let returned_value = closure(ExposedSecret[T](self.inner))
let new_self = Secret.ec_add_one(self^)
return [returned_value, new_self]

fn main():
alias orig = Secret[Int, 3](69)
let oomy_secret = Secret.ec_add_one(orig)
let omy_secret = Secret.ec_add_one(oomy_secret)
let my_secret = Secret.ec_add_one(omy_secret)

@parameter
fn capturing_closure_but_actually_never_capture(borrowed exposed_secret: ExposedSecret[Int]) -> Int:
return exposed_secret.borrowed_value

let my_69_secret_tuple = my_secret.expose_secret[Int](capturing_closure_but_actually_never_capture)
let returned_69_secret = my_69_secret_tuple.get[0, Int]()
let my_new_secret = my_69_secret_tuple.get[1, Secret[Int, 3, 3]]()
However, if you remove one of the first my_secrets and adjust the names appropriately, it will compile. So I think this is closer to fulfilling your goal; correct me if this is wrong though. Side note: It is strange that in the last .get call, you can change the EC and MEC type params in the Secret[Int, ...] part to be basically anything, and the compiler doesn't complain. However, if you change the initial type from Int to something else, it complains. I guess this might make sense considering the result type of the pesky MLIR operation kgen.pack.get cares about the types and might handle the value parameters differently, but it's still quite interesting.
11 replies
MModular
Created by b4rdarian on 10/24/2023 in #questions
Confusion with owned integers
I think the compiler's behavior on this isn't fully fleshed out, or blocked on traits, and that's why it worked with String when it ideally shouldn't
32 replies
MModular
Created by b4rdarian on 10/24/2023 in #questions
Confusion with owned integers
Even though you do have that object under y, x is now invalid
32 replies
MModular
Created by b4rdarian on 10/24/2023 in #questions
Confusion with owned integers
You can't use the original one declared because that was consumed by your function call, albeit it did pass ownership back when you assigned it to y in your Int example
32 replies
MModular
Created by b4rdarian on 10/24/2023 in #questions
Confusion with owned integers
Yeah, this is correct
32 replies
MModular
Created by seb on 10/22/2023 in #questions
List of memory-only structs
Yeah, Pointers to any type that isn't a "simple" struct (not register_passable) don't work. I wrote a more detailed explanation here: https://discord.com/channels/1087530497313357884/1098713601386233997/1164304975816556655, albeit for a slightly different use case. The main point is the same, if you want such a thing you're essentially just going to be managing the memory yourself. Here, you can mark Neuron with @register_passable, then maybe add a copy method that then copies the struct's Tensor over so we don't duplicate pointers, and other similar operations.
8 replies
MModular
Created by Sammi Turner on 10/4/2023 in #questions
Refactoring from DynamicVector to a different data structure?
DynamicVector's really for containers that change size a lot. Mojo has a Tuple type which has similar functionality to Python's tuple, and you can see it here: https://docs.modular.com/mojo/stdlib/builtin/tuple.html. However, I think that StaticTuple (https://docs.modular.com/mojo/stdlib/utils/static_tuple.html) actually could be better suited here, since it's for containers whose sizes don't change, and with homogenous types (Tuple can handle different types, which we don't need, and makes it a little more annoying to access elements). Something like this is likely what you're looking for.
from utils.static_tuple import StaticTuple
alias Tuple3I = StaticTuple[3, Int]

fn safecracker(start: Int, incs: Tuple3I) -> Tuple3I:
var vec = Tuple3I()
vec[0] = (start - incs[0]) % 100
vec[1] = (vec[0] + incs[1]) % 100
vec[2] = (vec[1] - incs[2]) % 100
return vec

fn main():
let vec0 = Tuple3I(54, 48, 77)
let result = safecracker(96, vec0)
print(result[0], result[1], result[2])
from utils.static_tuple import StaticTuple
alias Tuple3I = StaticTuple[3, Int]

fn safecracker(start: Int, incs: Tuple3I) -> Tuple3I:
var vec = Tuple3I()
vec[0] = (start - incs[0]) % 100
vec[1] = (vec[0] + incs[1]) % 100
vec[2] = (vec[1] - incs[2]) % 100
return vec

fn main():
let vec0 = Tuple3I(54, 48, 77)
let result = safecracker(96, vec0)
print(result[0], result[1], result[2])
3 replies
MModular
Created by Jake Brooks on 10/3/2023 in #questions
Possible to get a meaningful time value?
Whoops, sorry I didn't see this till now. sa-code's got it, though 😉
14 replies