Skip to content

Commit

Permalink
Thinking on python implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
FadiShawki committed Feb 19, 2024
1 parent 11b81f1 commit 581aba7
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 140 deletions.
132 changes: 4 additions & 128 deletions environments/python/_temp/Ray.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,11 @@ namespace Ray {
export type Listener = (event: Event) => void;
}

/**
* An uninitialized empty Ray, which caches itself once initialized.
*/
// export const None: Ray.FunctionConstructor<Ray.Any> = Ray.Function.CachedAfterUse(Ray.New);

// export class Object {
//
// // TODO: Could copy?
// get initial(): Ray.Any { return this._initial(); } set initial(initial: Ray.Any) { this._initial = initial; } protected _initial: Ray.Any;
// get self(): Ray.Any { return this._self(); } set self(self: Ray.Any) { this._self = self; } protected _self: Ray.Any;
// get terminal(): Ray.Any { return this._terminal(); } set terminal(terminal: Ray.Any) { this._terminal = terminal; } protected _terminal: Ray.Any;
//
// protected constructor({ initial, self, terminal }: { initial?: Ray.Any, self?: Ray.Any, terminal?: Ray.Any } = {}) {
//
// this._initial = initial ?? Ray.none.memoized;
// this._self = self ?? Ray.self_reference;
// this._terminal = terminal ?? Ray.none.memoized;
// }
// }

/** A simplistic compiler for Ray */
export namespace Compiler { // TODO Ray is Compiler

/**
* In the case of Rays, whether something is a vertex/initial/terminal is only inferred from surrounding context. And these checks only need to happen locally in order to decide how to traverse arbitrary structure (as in - I only need to check the presence of something next to me, not traverse the whole direction recursively in order to decide what to do).
*
*
* How about treating something like something which the context says it's not? (Could apply this sort of thing in some fidelity/consistency checking mechanism as a way of fuzzing the fidelity mechanism)
*
Expand Down Expand Up @@ -130,66 +110,6 @@ namespace Ray {

}


export namespace ProxyHandlers {

export const Default: ProxyHandler<Ray.Any> = JS.Class.Handler<Ray.Any>({
/** ray.property */
get: (self: Ray.Any, instance: Ray.Instance, property: string | symbol): any => {
instance.on({ event: 'PROXY.GET', context: { property } });

/** Use any field on {Ray.Instance}, which we want to delegate to, first. */
if (property === '___instance' || property === 'debug' || property === 'on') { return instance[property]; }

/** Otherwise, switch to functions defined on {Ray.Functions} */
const func = Ray.Function.Get(property as any);
if (func) { return func.as_method({ self, property }); }

if (property === Symbol.toPrimitive)
return (hint: string) => { return 100; }; // TODO: Can be used to setup label generation through javascript objects if we want to ? + allow search on this
// throw new NotImplementedError(``);

/** Not implemented. */
throw new NotImplementedError(`Called property '${String(property)}' on Ray, which has not been implemented.`);
},

/** ray.property = something; */
set: (self: Ray.Any, instance: Ray.Instance, property: string | symbol, value: any): boolean => {
instance.on({ event: 'PROXY.SET', context: { property, value } });

throw new NotImplementedError();
},

/** delete ray.property; */
deleteProperty: (self: Ray.Any, instance: Ray.Instance, property: string | symbol): boolean => {
instance.on({ event: 'PROXY.DELETE', context: { property } });

throw new NotImplementedError();
},

/** ray() is called. */
apply: (self: Ray.Any, instance: Ray.Instance, args: any[]): any => {
instance.on({ event: 'PROXY.APPLY', context: { args } });

throw new NotImplementedError(`${self}`);
},

/** new ray() */
construct: (self: Ray.Any, instance: Ray.Instance, args: any[]): object => {
instance.on({ event: 'PROXY.NEW', context: { args } });

throw new NotImplementedError(`${args.length} ${self}`);
},

/** property in ray; */
has: (self: Ray.Any, instance: Ray.Instance, property: string | symbol): boolean => {
instance.on({ event: 'PROXY.HAS', context: { property } });

throw new NotImplementedError(`${String(property)}`);
},
});
}

/** Ray is an Enum(eration) */
export namespace Enum {

Expand All @@ -211,40 +131,12 @@ namespace Ray {
/** Ray is a function (.next) */
export namespace Function {

/** {T} is just an example/desired use case. But it generalizes to any function. */
export type Type<T> = T | Ray.Any;

/** From which perspective the Function is implemented. */
enum Perspective {
None, Self, /** Ref, */
}

// /**
// * Implement a function from the perspective of 'this' for 'this.self'.
// */
// // static Ref = <TResult>(impl: (ref: Ray.Any) => TResult): Function<TResult> => Ray.Function.Self(self => impl(self.as_reference()));

/** Implement a function from no (or: an ignorant) perspective. */
export namespace None {

export const Impl = (impl: Op.Zeroary.Type<Ray.Any>): Ray.Any => {
throw new NotImplementedError();
// return new Ray.Any({ perspective: Perspective.None, impl });
}

}

/** Implement a function from the perspective of 'this' */
export namespace Self {
export const Impl = (impl: Op.Unary.Type<Ray.Any>): Ray.Any => {
throw new NotImplementedError();
// return new Ray.Any({ perspective: Perspective.Self, impl });
}

export const Binary = (impl: Op.Binary.Type<Ray.Any>): Ray.Any => {
throw new NotImplementedError();
// return new Ray.Any({ perspective: Perspective.Self, impl }); // TODO: Good way to deal with arity
}

// export const If = (impl: Op.Unary.Type<Ray.Any>): Ray.Any => {
// return Impl(impl); // TODO: GENERIC collapse to boolean implemented and overridable
Expand All @@ -260,25 +152,9 @@ namespace Ray {
// }
}
}

export namespace Function {
export const Get = <TProperty extends keyof (typeof Ray.Function.All)>(
property: TProperty
): (typeof Ray.Function.All)[TProperty] | undefined => Ray.Function.All[property as TProperty] ?? undefined;

export namespace All {

export const traverse = Ray.Function.Self.Impl(
(a) => { throw new NotImplementedError(); }
);

/**
* Any arbitrary direction, where .not (or reversing the direction) relies on some memory mechanism
*/
export const memoized = Ray.Function.Self.Impl(
self => { throw new NotImplementedError(); }
);
}
export const traverse = Ray.Function.Self.Impl(
(a) => { throw new NotImplementedError(); }
);

}

Expand Down
8 changes: 8 additions & 0 deletions environments/python/orbitmines/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ def test() -> Ray:
test.run(lambda ray: ray)
# Ray.runtime(lambda ray: ray).run(test)

# class Object(Ray):
# @property
# def initial(self) -> Ray: raise NotImplementedError
# @property
# def self(self) -> Ray: raise NotImplementedError
# @property
# def terminal(self) -> Ray: raise NotImplementedError

test.compile(lambda ray: ray)
Ray.compile(lambda ray: ray)

Expand Down
57 changes: 45 additions & 12 deletions environments/python/orbitmines/ray.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import inspect
from typing import Iterator, AsyncIterator, Union, Callable, Any, Iterable, AsyncIterable
from typing import Iterator, AsyncIterator, Union, Callable, Any, Iterable, AsyncIterable, Tuple


# TODO: Restrictive cases:
Expand All @@ -11,8 +11,22 @@

# TODO: Better python solution than just @ray everywhere (for typechecker)

def ray(func: Callable[[Any, ...], Any]) -> Ray: return func
def ray(func: Callable[[Any, ...], Any]) -> Ray:
pass

class Ray2:
def __getattr__(self, name: str) -> Any:
print(f'{name}')
pass
def __setattr__(self, key, value) -> Any:
print(f'{key}={value}')
pass

#
# In the case of Rays, whether something is a vertex/initial/terminal is only inferred from surrounding context. And these checks only need to happen locally in order to decide how to traverse arbitrary structure (as in - I only need to check the presence of something next to me, not traverse the whole direction recursively in order to decide what to do).
#
# @staticmethod: Implement a function from no (or: an ignorant) perspective.
# method(self): Implement a function from the perspective of 'this'
class Ray:
def __init__(self, *args, **kwargs):
pass
Expand All @@ -29,6 +43,7 @@ def __init__(self, *args, **kwargs):
def none() -> Ray: return -Ray.some
alloc = new = create = initialize \
= none

@staticmethod
@ray
def some() -> Ray: return -Ray.none
Expand Down Expand Up @@ -254,7 +269,7 @@ def add(a, b: Arbitrary) -> Ray: raise NotImplementedError
@ray
def radd(self) -> Ray: return -self.add.perspective
@ray
def sub(a, b: Arbitrary) -> Ray: raise NotImplementedError
def sub(a, b: Arbitrary) -> Ray: return -a.add
__sub__ \
= sub
@ray
Expand Down Expand Up @@ -306,17 +321,19 @@ def compiler() -> Ray: raise NotImplementedError
# Ray is a function (.next)
# TODO: In the case of tinygrad this is similar to .realize() ?
def __call__(self, *args, **kwargs) -> Ray:
print(f'__call__ {args} {kwargs}')
print(f'{self.name}.__call__ {args} {kwargs}')
# raise NotImplementedError
return self
map = render = compile = run \
= __call__

def __get__(self, instance, owner) -> Ray:
print(f'__get__ {instance} {owner}')
print(f'{self.name}.__get__ {instance} {owner}')
return self
# raise NotImplementedError
def __set__(self, instance, value) -> Ray: raise NotImplementedError
def __set__(self, instance, value) -> Ray:
print(f'{self.name}.__set__ {instance} {value}')
return self
def __delete__(self, instance) -> Ray: raise NotImplementedError

def __iter__(self) -> Iterator[Ray]: return self.as_iterator()
Expand Down Expand Up @@ -399,8 +416,10 @@ def __rfloordiv__(a, b: Arbitrary) -> Ray: return Ray(b).__floordiv__(a)
#

@staticmethod
def function(func: Callable[[Any, ...], Any]) -> Ray:
return Ray()
def function(name: str, func: Callable[[Any, ...], Any]) -> Ray:
a = Ray()
a.name = name
return a
@staticmethod
def integer(val: int) -> Ray: raise NotImplementedError
@staticmethod
Expand All @@ -424,6 +443,13 @@ def arbitrary(val: Arbitrary) -> Ray: raise NotImplementedError
# - TODO: readonly setup, where only traversal ops are allowed. Of course these are writing in some sense, but those writings aren't directly accessible from this perspective
def readonly() -> Ray: raise NotImplementedError

# Any arbitrary direction, where reversing the direction relies on some arbitrary memory mechanism
@ray
def memoized(self) -> Ray:
# TODO: something along the lines of:
# self.next.initial = self ;
raise NotImplementedError

# print(f'{type(func)}')
# def method(*args, **kwargs) -> Ray:
# return Ray()
Expand All @@ -432,15 +458,22 @@ def readonly() -> Ray: raise NotImplementedError
# TODO: Binary on self is (a, a) like is_orbit(a, a) ?

# By default a = -b is -b = a
# __sub__ = -__add__
# __add__ = -__sub__
# __set__(self, '')

for name, fn in inspect.getmembers(Ray, inspect.isfunction):
if name.startswith('__'): continue
print(f'{name}')
setattr(Ray, name, Ray.function(fn))
setattr(Ray, name, Ray.function(name, fn))

# a: Callable[[Ray], Ray] = lambda self: self.is_terminal
setattr(Ray, '__mul__', Ray.function(Ray.size))
setattr(Ray, '__mul__', Ray.function('__mul__', Ray.size))

print('----------------')
ray = Ray2()
ray.__init__ = lambda self: self
ray.__mul__ = 'test'
print('----------------')
# Ray.__add__ = -Ray.__sub__
# Ray.__sub__ = -Ray.__add__

Arbitrary = Union[int, Ray]

0 comments on commit 581aba7

Please sign in to comment.