Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Imperative interface #34

Open
rickardnorlander opened this issue Jun 10, 2022 · 6 comments
Open

Feature request: Imperative interface #34

rickardnorlander opened this issue Jun 10, 2022 · 6 comments

Comments

@rickardnorlander
Copy link
Contributor

rickardnorlander commented Jun 10, 2022

For me it would be more convenient to use an interface where I push probabilities into the coder, rather than the coder pulling them out of my model. I have a few different predictors, and they can take varying number of arguments of different types. With an imperative interface it would straightforward, I first encode which predictor to use and push it into the coder, then I push the arguments one by one. But with the callback pattern it becomes quite awkward. I have to do multiple passes and have one root model that interprets some symbols as a predictor id and others as argument and then route it correctly.

@danieleades
Copy link
Owner

danieleades commented Jun 10, 2022

Hi @rickardnorlander thank you for the feedback. I'd like to try and get a better understanding of your use case.

It is the intention of the (current) API in this library that the Model trait could be either a simple probability model, or a facade over a much more complex predictor. I'm struggling to imagine how the complexity or the logic change whether the decision of which sub-model to use (based on the history/context) is performed inside or outside of the Model facade.

It would be really helpful to see some code to be honest. Maybe you can show me the pattern you've had to use, and a counter example of how you'd like it to work?

@rickardnorlander
Copy link
Contributor Author

rickardnorlander commented Jun 10, 2022

Something like this maybe


for value in values {
    if predictor_0.predict() == value {
	ac.encode(meta_model.encode(PREDICTOR_0));
	continue;
    }
    
    if let Some(symbol) = predictor_1.try_encode(value) {
	ac.encode(meta_model.encode(PREDICTOR_1));
	ac.encode(symbol);
	continue;
    }
    
    let (symbol_1, symbol_2) = predictor_2.encode(value);
    if score(param_1, param_2) > threshold {
	ac.encode(meta_model.encode(PREDICTOR_2));
	ac.encode(symbol_1);
	ac.encode(symbol_2);
	continue;
    }
    
    ac.encode(meta_model.encode(LITERAL));
    ac.encode(AcParam(value..value+1, MAX_VALUE))
}







enum Intermediate {
    Predict1,
    Predict2(P2Symbol),
    Predict3(P2Symbol1, P2Symbol2),
    Literal(LiteralType),
};


let mut intermediates = Vec::new()
for value in values {
    if predictor_0.predict() == value {
	intermediates.push(Predict1());
	continue;
    }
    if let Some(symbol) = predictor_1.try_encode(value) {
	intermediates.push(Predict2(symbol));
	continue;
    }
    let (symbol_1, symbol_2) = predictor_2.encode(value);
    if score(param_1, param_2) > threshold {
	intermediates.push(Predict3(symbol_1, symbol_2))
	continue;
    }

    intermediates.push(Literal(value));
}


fn probability(
    &self,
        symbol: Option<&Self::Symbol>,
) -> Result<Range<Self::B>, ValueError> {
    if delegate == None {
	return ...
    }
    else {
	delegate.probability()
    }
}

fn symbol(
    &self,
        symbol: Option<&Self::Symbol>,
) -> Result<Range<Self::B>, ValueError> {
    if delegate == None {
	return ...
    }
    else {
	delegate.symbol()
    }
}


fn denominator(
    &self,
        symbol: Option<&Self::Symbol>,
) -> Result<Range<Self::B>, ValueError> {
    if delegate == None {
	return ...
    }
    else {
	delegate.denominator()
    }
}

fn update(
    &self,
        symbol: Option<&Self::Symbol>,
) -> Result<Range<Self::B>, ValueError> {
    if state == PredictorId {
	delegate = 
    }
    else {
	if delegate.update() {
	    delegate = none
	}
    }
}

@danieleades
Copy link
Owner

i haven't forgotten about this! I'm travelling at the moment, so haven't had a chance to look at it properly

@danieleades
Copy link
Owner

By the way @rickardnorlander, do you have any of this code on GitHub?

@rickardnorlander
Copy link
Contributor Author

It's for a lossless image compressor that I didn't make public yet because I haven't able to achieve the kind of compression I want (I beat png by a bit, but lose to modern ones like webp). Anyway I was able to hack together an interface for myself so I'm not blocked by this.

@danieleades
Copy link
Owner

I'd prefer you weren't just unblocked, but that you had a solution that was nice.

I was going to suggest creating an iterator adaptor, or something along those lines, which folded your low-level symbols into the 'intermediate' symbols

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants