Skip to content

A collection of tools and utilities that I often use in my work. 🔧🧰

License

Notifications You must be signed in to change notification settings

lunaluxie/luxtools

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

LuxTools

A collection of tools and utilities that I often use in my work.

Features

Installation

pip install luxtools

Usage

Scientific

Error Propagation

import torch
from luxtools import get_error

# Create tensors with uncertainties
x = torch.tensor([1.0, 3.0], dtype=torch.float32, requires_grad=True)
x.sigma = torch.tensor([0.1, 0.2], dtype=torch.float32)

y = torch.tensor([2.0, 4.0], dtype=torch.float32, requires_grad=True)
y = Variable(y, torch.tensor([0.2, 0.3]))

# Perform calculations
f = x * y

# Get propagated error
error = get_error(f)
# tensor([0.2828, 1.2042])

Numeric Result Formatting

from luxtools import NumericResult

# Create a measurement with uncertainty
result = NumericResult(1.234, 0.193)
print(result)
# (1.2 ± 0.2)

# Scientific notation
result = NumericResult(234.23424, 10)
print(result)
# (2.3 ± 0.1)*10^(2)

# LaTeX output
print(result.latex())
# (2.3 \pm 0.1)\cdot 10^{2}

Functional

Function Composition

from luxtools import chain

# Compose functions
f = lambda x: x + 1
g = lambda x: x * 2
h = lambda x: x ** 2

# Create a new function that applies f, then g, then h
composed = chain(f, g, h)

result = composed(3)  # ((3 + 1) * 2) ** 2 = 64

Partial Application

Allows you to partially apply arguments to a function, creating a new function with fewer arguments. See article for discussion.

from luxtools import partial

@partial
def greet(greeting, name):
    return f"{greeting}, {name}!"

# Create a new function with 'Hello' fixed as the greeting
say_hello = greet("Hello")

result = say_hello("World")  # "Hello, World!"

Overload function definitions

Allows you to have multiple function definitions for the same function name. It uses typehints to determine which function to call. See article for discussion.

from luxtools import overload

class Email:
    def __init__(self, email: str):
        self.email = email

    def __str__(self) -> str:
        return self.email


class PhoneNumber:
    def __init__(self, phone_number: str):
        self.phone_number = phone_number

    def __str__(self) -> str:
        return self.phone_number


@overload
def get_user(email: Email):
    print("Email:", email)
    return email


@overload
def get_user(phone_number: PhoneNumber):
    print("Phone:", phone_number)
    return phone_number

get_user(Email("[email protected]"))  # prints: Email: [email protected]
get_user(PhoneNumber("123-456-789"))  # prints: Phone: 123-456-789

Caveat, if the function is defined in a non-global scope such as a class, or inside a function, then you need to pass the local scope to the decorator.

def local_scope():
    @overload(scope=locals())
    def get_user(email: Email):
        print("Email:", email)

    @overload(scope=locals())
    def get_user(phone_number: PhoneNumber):
        print("Phone:", phone_number)

This is necessary because the parent stack frame doesn't exist inside the overload function, so it has to be passed explicitly. See tests.

About

A collection of tools and utilities that I often use in my work. 🔧🧰

Resources

License

Stars

Watchers

Forks

Languages