2021-10-24 19:33:08 +02:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# IMPORTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
from local . maths import * ;
from local . typing import * ;
from code . core . log import * ;
from code . algorithms . methods import * ;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# GLOBAL VARIABLES/CONSTANTS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# CHECKS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def preChecks ( L : List [ int ] , * * _ ) :
assert len ( L ) > 0 , ' Liste darf nicht leer sein. ' ;
return ;
def postChecks ( L : List [ int ] , * * _ ) :
# TODO
return ;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM max sub sum
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos ( name = ' MaxSubSum (Maximale Teilsumme) ' , outputnames = ( ' maxSum ' , ' index_from ' , ' index_to ' ) , checks = True , metrics = True , preChecks = preChecks , postChecks = postChecks )
def MaxSubSum ( L : List [ float ] ) - > Tuple [ float , int , int ] :
'''
Inputs : L = Liste von Zahlen
2021-10-26 13:39:58 +02:00
2021-10-24 19:33:08 +02:00
Outputs :
- maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente
- u , v = Indexes so dass die Teilliste [ L [ u ] , L [ u + 1 ] , . . . , L [ v ] ] die maximale Summe aufweist
'''
maxSum : float = 0 ;
u : int = 0 ;
2021-10-25 12:33:57 +02:00
v : int = - 1 ;
2021-10-24 19:33:08 +02:00
for i in range ( len ( L ) ) :
2021-10-25 12:33:57 +02:00
## Bestimme maximale Teilsumme der linken Rände der Liste ab Index i:
maxSum_ , _ , k = lRandSum ( L [ i : ] ) ;
if maxSum_ > maxSum :
k + = i ; # NOTE: muss wegen Offset kompensieren
maxSum , u , v = maxSum_ , i , k ;
logDebug ( ' max Teilsumme aktualisiert: Summe L[i] von i= {u} .. {v} = {value} ' . format ( u = u , v = v , value = maxSum ) ) ;
return maxSum , u , v ;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ALGORITHM max sub sum (D & C)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@algorithmInfos ( name = ' MaxSubSum (Maximale Teilsumme mit D & C) ' , outputnames = ( ' maxSum ' , ' index_from ' , ' index_to ' ) , checks = True , metrics = True , preChecks = preChecks , postChecks = postChecks )
def MaxSubSumDC ( L : List [ float ] ) - > Tuple [ float , int , int ] :
'''
Inputs : L = Liste von Zahlen
2021-10-26 13:39:58 +02:00
2021-10-25 12:33:57 +02:00
Outputs :
- maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente
- u , v = Indexes so dass die Teilliste [ L [ u ] , L [ u + 1 ] , . . . , L [ v ] ] die maximale Summe aufweist
'''
maxSum = 0 ;
u = 0 ;
v = - 1 ;
if len ( L ) == 1 :
## wenn Liste aus 1 Element besteht, nicht teilen:
if L [ 0 ] > maxSum :
v = 0 ;
maxSum = L [ 0 ] ;
else :
u = math . ceil ( len ( L ) / 2 ) ;
Ll = L [ : u ] ;
Lr = L [ u : ] ;
## berechnet maximale Teilsumme der linken Hälfte:
maxSum1 , u1 , v1 = MaxSubSumDC ( L = Ll ) ;
## berechnet maximale Teilsumme der rechten Hälfte:
maxSum2 , u2 , v2 = MaxSubSumDC ( L = Lr ) ;
u2 , v2 = u2 + len ( Ll ) , v2 + len ( Ll ) ; # offsets kompensieren
## berechnet maximale Teilsumme mit Überschneidung zw. den Hälften:
maxSum3 , u3 , v3 = lrRandSum ( Ll = Ll , Lr = Lr ) ;
## bestimme Maximum der 3 Möglichkeiten:
maxSum = max ( maxSum1 , maxSum2 , maxSum3 ) ;
if maxSum == maxSum1 :
maxSum , u , v = maxSum1 , u1 , v1 ;
logDebug ( ' max Teilsumme kommt in linker Partition vor: Summe L[i] von i= {i} .. {j} = {value} ' . format ( L = L , i = u , j = v , value = maxSum ) ) ;
elif maxSum == maxSum3 :
maxSum , u , v = maxSum3 , u3 , v3 ;
logDebug ( ' max Teilsumme kommt in Überschneidung vor: Summe L[i] von i= {i} .. {j} = {value} ' . format ( L = L , i = u , j = v , value = maxSum ) ) ;
else : # elif maxSum == maxSum2:
maxSum , u , v = maxSum2 , u2 , v2 ;
logDebug ( ' max Teilsumme kommt in rechter Partition vor: Summe L[i] von i= {i} .. {j} = {value} ' . format ( L = L , i = u , j = v , value = maxSum ) ) ;
return maxSum , u , v ;
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# AUXILIARY METHODS
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def lrRandSum ( Ll : List [ float ] , Lr : List [ float ] ) - > Tuple [ float , int , int ] :
'''
Bestimmt maximale Teilsumme einer Teiliste einer Liste ,
wobei die Liste in zwei Intervalle partitioniert ist
und die Teilliste beide überschneidet .
Inputs : Ll , Lr = eine Partition einer Liste von Zahlen in zwei Intervalle
Outputs : maxSum , u = 0 , v
'''
maxSumL , u , _ = rRandSum ( L = Ll ) ;
maxSumR , _ , v = lRandSum ( L = Lr ) ;
maxSum = maxSumL + maxSumR ;
v + = len ( Ll ) # offsets kompensieren
return maxSum , u , v ;
def lRandSum ( L : List [ float ] ) - > Tuple [ float , int , int ] :
'''
Bestimmt maximale Teilsumme aller nicht leeren linken Segmente einer Liste .
Inputs : L = Liste von Zahlen
Outputs : maxSum , u ( = 0 ) , v
'''
n = len ( L ) ;
## berechne kumulative Summen (vorwärts)
AddToCounter ( n ) ;
total = L [ 0 ] ;
maxSum = total ;
u = 0 ;
v = 0 ;
for i in range ( 1 , n ) :
total + = L [ i ] ;
if total > maxSum :
v = i ;
maxSum = total ;
return maxSum , 0 , v ;
def rRandSum ( L : List [ float ] ) - > Tuple [ float , int , int ] :
'''
Bestimmt maximale Teilsumme aller nicht leeren rechten Segmente einer Liste .
Inputs : L = Liste von Zahlen
Outputs : maxSum , u , v ( = len ( L ) - 1 )
'''
n = len ( L ) ;
## berechne kumulative Summen (rückwärts)
AddToCounter ( n ) ;
total = L [ n - 1 ] ;
maxSum = total ;
u = n - 1 ;
v = n - 1 ;
for i in range ( 0 , n - 1 ) [ : : - 1 ] :
total + = L [ i ] ;
if total > maxSum :
u = i ;
maxSum = total ;
2021-10-24 19:33:08 +02:00
return maxSum , u , v ;
2021-10-26 13:39:58 +02:00
# Sei N ∈ ℕ⁺
# Sei p so, dass 2^p ≤ N < 2^{p+1},
# Also p = floor(log₂(N)).
# Setze
# B(i,d) := {k < N | bit(k, i) = d}
# für i ∈ {0, 1, ..., p-1}
# und setze
# 𝒜 = {B(i,d) : i ∈ {0, 1, ..., p-1}, d ∈ {0,1}}.
# Seien k1, k2 ∈ N mit k1 ≠ k2.
# Dann existiert i ∈ {0, 1, ..., p-1},
# so dass
# d := bit(k1, i) ≠ bit(k2, i).
# Also
# k1 ∈ B(i, d) ∌ k2.
# Darum erfüllt 𝒜 die erwünschte Eigenschaft.
# Es gilt
# |𝒜 | = 2p = 2·floor(log₂(N)) ∈ O(log(N)).