def distance_to_next_change(boxes: List[Any], idx: int) -> Optional[int]: """Given a sequence and an index, find the number of elements to the next value that's different from the current one. """ remboxes = boxes[idx:] + [None] dist = fn.ilen(fn.takewhile(lambda b: b == boxes[idx], remboxes)) if remboxes[dist] is None: return None return dist
def read_config_header(filepath, defaults=None, encoding=DEFAULT_ENCODING): filepath = Path(filepath) if not has_config_header(filepath): return defaults.copy() if defaults else {} else: with open(filepath, mode="r", encoding=DEFAULT_ENCODING) as fi: header = "".join( fn.takewhile( fn.none_fn( fn.rpartial(str.startswith, "---\n"), fn.rpartial(str.startswith, "...\n"), ), fn.rest(fi), ) ) return parse_config(header, defaults)
def to_digits(number: int) -> Iterable[int]: return map(int, str(number)) def is_bouncy(number: int) -> bool: pairwise_digits = list(pairwise(to_digits(number))) return (not all(a >= b for (a, b) in pairwise_digits)) \ and (not all(a <= b for (a, b) in pairwise_digits)) State = namedtuple('State', 'i num_of_bouncy proportion_of_bouncy') def step(prev: State) -> State: i = prev.i + 1 num_of_bouncy = int(is_bouncy(i)) + prev.num_of_bouncy return State(i, num_of_bouncy, proportion_of_bouncy=num_of_bouncy / i) if __name__ == '__main__': initial_state = State(i=1, num_of_bouncy=0, proportion_of_bouncy=0) result = rcompose( lambda: iterate(step, initial_state), lambda xs: takewhile(lambda x: x.proportion_of_bouncy <= 0.99, xs), last)() print(result)
def competence(request): def same_as_canonical(raw_annotation): return is_samples_concordant(raw_annotation, raw_annotation.canonical) if request.user.is_competent: return redirect(validate) if request.method == 'POST': canonical_id = request.POST['canonical_id'] data = { 'user_id': request.user.id, 'column': request.POST['column'], 'regex': request.POST['regex'], 'annotations': dict(json.loads(request.POST['values'])), 'is_active': False, 'by_incompetent': True, } # Save validation marking by_incompetent try: save_validation(canonical_id, data) except AnnotationError as err: messages.error(request, str(err)) return redirect(competence) # Check how many tries and progress = number of successful tries in a row annotations = RawSeriesAnnotation.objects.filter(created_by=request.user, by_incompetent=True) \ .order_by('-id')[:5] \ .prefetch_related('sample_annotations', 'canonical', 'canonical__sample_annotations') first_try = len(annotations) == 0 annotations = list(takewhile(same_as_canonical, annotations)) progress = len(annotations) # 5 successful tries in a row is test pass if progress >= 5: request.user.is_competent = True request.user.save() messages.success( request, '''Congratulations! You passed competence test.<br> You can now annotate and validate series.''' ) return redirect(validate) # Welcome, progress and fail messages if progress == 0 and first_try: messages.info( request, '''Welcome to competence test!<br> You need to annotate 5 series in a row correctly to pass.''' ) elif progress == 0 and not first_try: messages.error( request, '''This one was wrong, sorry.<br> Starting from zero with fresh series.''') elif progress == 4: messages.success(request, '''You are almost there! Here is the last one.''') elif progress == 3: messages.success(request, '''Good progress, only 2 annotations left.''') else: messages.success(request, '''Correct! %d series to go.''' % (5 - progress)) # Select canonical annotation to test against # NOTE: several conditions play here: # - exclude annotations seen before # - only use agreed upon ones (best_cohens_kappa = 1 means there are 2 concordant annos) # - first 3 tries select non-controversial annotations (fleiss_kappa = 1) # - exclude tags seen in this test run # - last 2 tries select less obvious annotations (fleiss_kappa < 1) # - 2 of all tests should use captive tags qs = SeriesAnnotation.objects.exclude(raw_annotations__created_by=request.user) \ .filter(best_cohens_kappa=1) \ .select_related('series_tag', 'series_tag__tag') # These conds are lifted until some test material is found conds = [Q(fleiss_kappa=1) if progress < 3 else Q(fleiss_kappa__lt=1)] seen_tags = [a.tag_id for a in annotations] if seen_tags: conds += [~Q(tag__in=seen_tags)] if progress == 0: conds += [Q(captive=False)] else: captive_left = 2 - sum(a.canonical.captive for a in annotations) conds += [Q(captive=random.randint(0, 5 - progress) < captive_left)] canonical = get_sample(qs, conds) if canonical is None: messages.error(request, '''Too many tries, we are out of test material.''') return redirect(validate) samples, columns = fetch_annotation_data(canonical.series_id, canonical.platform_id, blind=BLIND_FIELDS) return { 'canonical': canonical, 'series': canonical.series, 'tag': canonical.tag, 'columns': columns, 'samples': samples, 'progress': progress }
def sees_stars(self): parents = takewhile(bool, iterate(lambda s: s.parent, self)) return any(s.has_stars for s in parents)