Accomplishing shareValue/shareBehavior - rxjs5

I have an Observable that is based on some events and at some point does some expensive computation. I would like to render the results from that Observable in multiple different places. If I naively subscribe to this Observable in two places I will end up doing the expensive computation twice. Here is a code snippet to drive my point home:
var s = new rx.Subject();
var o = s.map(x => { console.log('expensive computation'); return x });
o.subscribe(x => console.log('1: ' + x));
o.subscribe(x => console.log('2: ' + x));
s.next(42);
The output is:
expensive computation
1: 42
expensive computation
2: 42
I would like to perform the expensive computation in the map only once. share accomplishes this, but it makes it so late-arriving subscribers do not get the current value to render. In previous RxJS versions, shareValue allowed late-arriving subscribers to get the current value. However, it appears that this was renamed to shareBehavior in RxJS 5 and then removed altogether:
https://github.com/ReactiveX/rxjs/pull/588
https://github.com/ReactiveX/rxjs/pull/712
There is a long discussion in this issue where it was decided that they would 'Remove shareBehavior and shareReplay to prevent user confusion.' I don't understand what the potential for confusion was (so maybe that means I am one of the users saved by this decision?).
publishBehavior also looks promising but I don't fully understand publish and it seems like it adds more complexity than I need or want.
Anyway, I would like to know if there is a recommended way to accomplish this in RxJS 5. The migration doc doesn't provide any recommendations.

After some more research I've found that the behavior I've described can be implemented with
.publishBehavior(startValue).refCount().
This discovery is based on the fact that share() is an alias for publish().refCount(). I still don't fully understand publish() but this seems to have the desired effect in practice.
Similar is cache(1) (which is an alias for publishReplay(1).refCount()). It has a similar effect as publishBehavior(defaultValue).refCount() except that it does not start with a default value. So if no items have been emitted, new subscribers will not immediately receive a value.

Related

Parameters for dlib::find_min_bobyqa

I'm working on the C++ version of Matt Zucker's Page dewarping. So far everything works fine, but I have a problem with optimization. In line 748 of Github repo Matt uses optimize function from Scipy. My C++ equivalent is find_min_bobyqa from dlib.net. The code is:
auto f = [&](const column_vector& ppts) { return objective( dstpoints, ppts, keypoint_index); };
dlib::find_min_bobyqa(f,
params,
2 * params.nr() + 1, // npt - number of interpolation points: x.size() + 2 <= npt && npt <= (x.size()+1)*(x.size()+2)/2
dlib::uniform_matrix<double>(params.nr(), 1, -2), // lower bound constraint
dlib::uniform_matrix<double>(params.nr(), 1, 2), // upper bound constraint
1, // initial trust region radius
1e-5, // stopping trust region radius
4000 // max number of objective function evaluations
);
In my concrete example params is a dlib::column_vector with double values and length = 189. Every element of params is less than 2.0 and greater than -2.0. Function objective() returns double value and "alone" it works properly because I get the same value as in the Python version. But after running fin_min_bobyqa function I usually get the message:
Terminate called after throwing an instance of 'dlib:bobyqa_failure', return from BOBYQA because the objective function has been called max_f_evals times.
I set max_f_evals to quite big value to see if it optimizes at all, but it doesn't. I did some tweaking with parameters but without good results. How should I set the parameters of find_min_bobyqa to get the right solution?
I am very interested in this issue as well. Zucker's work, with very minor tweaks, is ideal for straightening sheet music images, and I was looking for ways to implement it in a mobile platform when I came across your question.
My research so far suggests that BOBYQA is not the equivalent of Powell's method in scipy. BOBYQA is constrained, and the one in scipy is not.
See these links for more information, and a possible way to compile the right supporting library - I would try UOBYQA or NEWUOA.
https://github.com/jacobwilliams/PowellOpt
https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.minimize.html#rdd2e1855725e-3
(See the Notes section)
EDIT: see C version here:
https://github.com/emmt/Algorithms/tree/master/newuoa
I wanted to post this as a comment, but I don't have enough points for that.
I am very interested in your progress. If you're willing, please keep me posted.
I finally solved this problem. I used PRAXIS library, because it doesn't need derivative information and is fast.
I modified the code a little to my needs and now it is faster around few seconds than original version written in Python.

RxJS Observables: new request depending on previous result

How can I generate new values to an Observable or Subject depending on received values?
Example:
Let's say I have an Observable that emits one random number thanks to a web API.
If it is an even number, I want the Observable to emit another random number using the first one as a seed... and so on until I get an odd value.
Note that I don't know in advance how many requests I'm going to make.
Until now, I managed to do it with "weird", recursive methods, but I feel like there must be a much proper way to do this.
Seems like you can use expand() for this.
const source$ = /* some API call that returns an Observable */;
source$.pipe(
expand((previous: number) => previous % 2 === 0 ? source$ : EMPTY),
takeLast(1),
).subscribe(console.log);
This gives you only the last value (the first odd). If you want to get all the intermediate values as well just remove that takeLast(1).
Live demo: https://stackblitz.com/edit/rxjs-czomtm

Logging and asserting the number of previously-unknown DOM elements

I'ts my first tme using Cypress and I almost finalized my first test. But to do so I need to assert against a unknown number. Let me explain:
When the test starts, a random number of elements is generated and I shouldn't have control on such a number (is a requirement). So, I'm trying to get such number in this way:
var previousElems = cy.get('.list-group-item').its('length');
I'm not really sure if I'm getting the right data, since I can not log it (the "cypress console" shows me "[Object]" when I print it). But let's say such line returns (5) to exemplify.
During the test, I simulate a user creating extra elements (2) and removing an (1) element. Let's say the user just creates one single extra element.
So, at the end os the test, I need to check if the number of eements with the same class are equals to (5+2-1) = (6) elements. I'm doing it in this way:
cy.get('.list-group-item').its('length').should('eq', (previousTasks + 1));
But I get the following message:
CypressError: Timed out retrying: expected 10 to equal '[object Object]1'
So, how can I log and assert this?
Thanks in advance,
PD: I also tryed:
var previousTasks = (Cypress.$("ul").children)? Cypress.$("ul").children.length : 0;
But it always returns a fixed number (2), even if I put a wait before to make sure all the items are fully loaded.
I also tryed the same with childNodes but it always return 0.
Your problem stems from the fact that Cypress test code is run all at once before the test starts. Commands are queued to be run later, and so storing variables as in your example will not work. This is why you keep getting objects instead of numbers; the object you're getting is called a chainer, and is used to allow you to chain commands off other commands, like so: cy.get('#someSelector').should('...');
Cypress has a way to get around this though; if you need to operate on some data directly, you can provide a lambda function using .then() that will be run in order with the rest of your commands. Here's a basic example that should work in your scenario:
cy.get('.list-group-item').its('length').then(previousCount => {
// Add two elements and remove one...
cy.get('.list-group-item').its('.length').should('eq', previousCount + 1);
});
If you haven't already, I strongly suggest reading the fantastic introduction to Cypress in the docs. This page on variables and aliases should also be useful in this case.

How to push array elements asynchronously

I'm looking for a simple way to push array elements asynchronously every second. This code works fine - it sends 2 and in a second 55:
Rx.Observable.from([2, 55])
.zip(Rx.Observable.interval(1000), x => x);
Is there a simpler way to do the same thing?
Thank you.
If you use rxjs v4, you can make use of Rx.Observable.generateWithAbsoluteTime. It is basically a for loop with varying time.
Or you could use interval like here :
Rx.Observable.interval(1000).take(yourArray.length).map(index => yourArray[index])
What I dont know is if it is simpler.
Use toArray()
Rx.Observable
.interval(1000)
.take(3)
.toArray()
.subscribe(x=>console.log(x))
Have a look at combineLatest and withLatestFrom but this really depends what you're trying to do.
By the way, using .zip in this situation is probably not ideal because .zip emits only when it has Nth item from all source Observables which is what you usually don't want.

Get last value from incomplete observable

There is an incomplete observable which can have or not have a replay of n values. I would like to get the last value from it - or just the next one if there is none yet.
This works for first available value with first() and take(1) (example):
possiblyReplayedIncomplteObservable.first().toPromise().then(val => ...);
But for the last value both last() and takeLast(1) wait for observable completion - not the desirable behaviour here.
How can this be solved? Is there a specific operator for that?
I had a solution for ReplaySubject(2) that 'drains' the sequence to get the latest element and if the sequence is empty simply takes the last element, yet, it was cumbersome and did not scale well (for example, if you decide to increase the replay size to 3). I then remembered that Replay/Behavior subjects tend to be hard to manage when they are piped. The simplest solution to that is to create a 'shadow' sequence and pipe your ReplaySubject into it (instead of creating it by transformation/operation on your ReplaySubject), hence:
var subject$ = new Rx.ReplaySubject(3);
var lastValue$ = new Rx.ReplaySubject(1);
subject$.subscribe(lastValue$); // short hand for subject$.subscribe(v => lastValue$.next(v))
lastValue$.take(1).toPromise().then(...);
========== Old solutions, ignoring the ReplaySubject(2) =================
After reading the comment below, the correct code is:
Rx.Observable.combineLatest(possiblyReplayedIncomplteObservable).take(1).subscribe(...)
and not
Rx.Observable.combineLatest(possiblyReplayedIncomplteObservable).subscribe(...)
This is due to the fact the promise is a "one time" observable. I think the toPromise() code resolves the result only on completion.
The take(1) will not affect your original stream since it operates on the new stream which is created by combineLatest.
And actually, the simplest way is:
possiblyReplayedIncomplteObservable.take(1).toPromise().then(...)

Resources