Generizität: Difference between revisions

From Alda
Jump to navigationJump to search
No edit summary
No edit summary
Line 1: Line 1:
                    
                    


== Definition in der Informatik :==
== Generzität :==




  Algortihmen und Datenstrukturen so zu entwerfen und implementieren, dass sie möglichst<br/> vielvältig verwendbar sind.
  Algortihmen und Datenstrukturen so zu entwerfen und implementieren, dass sie möglichst<br/> vielvältig verwendbar sind.


=== Gemeint sind : ===
'''Gemeint sind :'''


*verschiedene Anwendungen                         
*verschiedene Anwendungen                         
Line 13: Line 13:


--> ''' ohne Neuimplemenation '''
--> ''' ohne Neuimplemenation '''
*Code austauschen in Bibliotheken
*Code austauschen in Bibliotheken


Line 19: Line 18:
'''Beispiel : ''' Kopieren eines Containers
'''Beispiel : ''' Kopieren eines Containers


==== 1.Variante: ====


  def copyArray(a):
  def copyArray(a):
Line 27: Line 24:
   r.append(k)
   r.append(k)
  return k
  return k
==== 2.Variante: ====


  class Node :
  class Node :
Line 36: Line 30:
     self.next = next
     self.next = next
   return k
   return k
==== 3.Variante: ====


  def copyArrayToList(a) :
  def copyArrayToList(a) :
Line 45: Line 37:
       last.next = Node(k, None)
       last.next = Node(k, None)
       last = last.next
       last = last.next
    return first


==== 4.Variante: ====
 
  def copyListToArray(l):
  def copyListToArray(l):
     r = []
     r = []
Line 69: Line 60:




Wie kann man so zwischen einem Array und einer Liste navigieren, so dass man den Unterschied nicht mehr merkt?
'''Vereinheitlichung der Zieldatenstruktur :'''
 
-->''' Vereinheitlichung der Zieldatenstruktur :'''
 
*standardisierte Funktion "append"
*standardisierte Funktion "append"
*Array hat sie schon
*Array hat sie schon
Line 82: Line 70:
  class DoublyLinkedNode:
  class DoublyLinkedNode:
   def__init__(self,data = sentinelTag(), next = None)
   def__init__(self,data = sentinelTag(), next = None)
    if next is None:
      self.data =data
    self.prev = self.next = self
      if next is None:
    else :
            self.prev = self.next = self
    self.next = next
      else:
    self.prev = next.prev
            self.next = next
    next.prev.next = self
            self.prev = next.prev
    next.prev = self
            next.prev.next = self
            next.prev = self
 
def isSentinel(self) : return isinstance(self.data, SentinelTag)


def isSentinel(self) : return isinstance(self.data, sentinelTag)


class DoublyLinkedList :  # Realisiert doppelt verbundene kreisförmige Kette mit Seninel als Anker
 
      def__init__(self):
            self.sentinel = DoublyLinkedNode()
            self.size = 0


class DoublyLinkedList :
      def__len__(self): return self.size  #len(l)
  def__init__(self):
    self.sentinel = DoublyLinkedNode()
    self.size = 0


def__len__(self): return self.size  #len(l)
      def append(self, value):
def append(self, value):
          DoublyLinkedNode(value, self.sentinel)
    DoublyLinkedNode(value, self.sentinel)
          self.size += size
   def__iter__(self):
    
       return ListIterator(self.sentinel.next)
      def__iter__(self):
            return ListIterator(self.sentinel.next)
        
      def reverseIterator(self):
            return ListIterator(self.sentinel.prev)




=== 2. Navigation in der Quelldatenstruktur(<u>Iteration</u>) soll<br/> für alle Datenstrukturen funktionieren ===
2. Navigation in der Quelldatenstruktur(<u>Iteratoren</u>) soll<br/> für alle Datenstrukturen funktionieren


*Objekt, dass auf ein Element des Containers zeigt
*Objekt, dass auf ein Element des Containers zeigt
*zum nächsten Element weiter rücken kann
*Zum nächsten Element weiter rücken kann
*anzeigt, wenn das Ende der Sequenz erreicht ist  
*anzeigt, wenn das Ende der Sequenz erreicht ist  




  def genericCopy(quelle, ziele) :
  def genericCopy(quelle, ziele) :
    for k in quelle :
      for k in quelle :
    ziel.append(k)
            ziel.append(k)
   return ziel
   return ziel
liste = genericCopy(array, DoublyLinkedList())
<u> Statt copyArrayToList </u>
array2 = genericCopy(array,[])
<u> Statt copyArray </u>
array3 = genericCopy(liste,[])
<u> Statt copyListToArray </u>


   
   
  '''was tun''' " for k in quelle":
  liste = genericCopy(array, DoublyLinkedList())      # Statt copyArrayToList
  iter = quelle__iter__()
  array2 = genericCopy(array,[])                       # Statt copyArray
  try :
array3 = genericCopy(liste,[])                       # Statt copyListToArray
    while True :
    k = iter.next()
    ...# Schleifeninhalt
    except StopIteration: pass




Line 153: Line 136:
       self__class__(self.node)
       self__class__(self.node)


'''Was tut Python bei''' " for k in quelle":
iter = quelle__iter__()
try :
        while True :
              k = iter.next()
              ...          # Schleifeninhalt
except StopIteration: pass
'''Rückwärts kopieren :'''


  class ReverseListIterator(ListIterator)
  class ReverseListIterator(ListIterator)
   def next(self):
   def next(self):
      if self.node isSentinel(): raise StopIteration()
        if self.node isSentinel(): raise StopIteration()
       r = self.node.data
       v = self.node.data
       self.node = self.node.prev
       self.node = self.node.prev
       return r
       return v




  revarray = genericCopy(list, reverseIter()[]),
  revArray = genericCopy(list, reverseIter(), []),
  revlist = genericCopy(reversed(array), DoublyLinkedList())
  revList = genericCopy(reversed(array), DoublyLinkedList())




Line 176: Line 172:


  def maxList(l):
  def maxList(l):
     m = -1111111
     m = -1111111111111111
     while l is not None [not l is Sentinel(l)]
     while not l isSentinel:
         m = max(m, l.data)                    # max ist eingebaute Funkion in Python
         m = max(m, l.data)                    # max ist eingebaute Funkion in Python
         l =l.next
         l =l.next


===3.Funktoren===


'''Zur Verallgemeinerung werden Funktoren eingerichtet:'''
'''Zur Verallgemeinerung werden Funktoren eingerichtet:'''


*Funktor muss "callable" sein :
*Funktor muss "callable" sein : falls f Funktor ist, funktioniert v = f(a1, a2,...)  
falls f Funktor: v = f(a1, a2)
*Funktion, oder Objekt bei dem die Funktion __call___ definiert ist.
'''callable''' ist z.B. eine Funktion
 


*Objekt wo __call___ definiert
def doSomethingGeneric(functor,iterator, intial):
      for k in iterator
            initial = functor(initial, k)
    return initial


'''Statt maxList:'''


  def doSomethingGeneric(functor, iterator, for k in iterator: intial):
  m = doSomethingGeneric(max,list -11111111111)
    initial = functor(initial, k)
    return initial


m = doSomethingGeneric(max,list -1111111)
'''Statt sumArray :'''
statt maxList


  def add(x,y) return x+y
  def add(x,y): return x + y
   s = doSomethingGeneric(add, array,o)
   s = doSomethingGeneric(add, array,o)
statt sumArray
 
'''Statt genericCopy :'''


  def append(x,y):
  def append(x,y):
Line 208: Line 206:


  array4 = doSomethingGeneric(append, array[])
  array4 = doSomethingGeneric(append, array[])
  <u>Statt genericCopy</u>
   
 
'''doSomethingGeneric'''() gibt es in vielen Programmiersprachen


*'''doSomethingGeneric'''() gibt es in vielen Programmiersprachen
    *in Python : reduce   
    *in C++ : accumulate
    ...funktionale Sprachen (Lisp, Haskell...)


**in Python : reduce      in C++ : accumulate
'''verwandte generische Funktionen'''


'''verwandte generische Funkionen'''
map:


map: [x1, x2,...] --> [f(x1),f(x2),...]   alle funktionalen Sprachen ( Haskell,Lisp,...)
[x1, x2,...] --> [f(x1),f(x2),...]         # Funktor mit einem Argument


map  ist in C++ "transform"




===Offered Interface versus Required Interface===
===Offered Interface versus Required Interface===




'''Interface:'''
'''Interface:'''
*standardisierte Schnittstelle zwischen Algorithmen und Datenstruktur
*standardisierte Schnittstelle zwischen Algorithmen und Datenstruktur


Line 266: Line 266:
====Konzepte ( + Hierarchie)====
====Konzepte ( + Hierarchie)====


*copy Constructible ( P: copy.deepcopy)
* copy Constructible ( P: copy.deepcopy)
*Default Constructible
* Default Constructible (v1 = v.__class__() ist aufrufbar ) # DoublylinkedNode
* EqualityComparable('=='), LessThanComparable('<')
* ThreeWayComparable(__cmp__ ist aufrufbar)
* Indexable("a[k]", k ist Integer)
* Mapping("a[key]", key ist arbitrary)
* Hashable(__hash__ für key)


v1 = v.__class__()  # DoublylinkedNode


*EqualityComparable('=='), LessThanComparable('<')
ThreeWayComparable(__cmp__)


* Iteratoren : Forward(next), BidirektionalIterator(next, prev), RandomAccessIterator(nex(k))


* Indexable("a[k]")
* Mapping("a[key]")




* Iteratoren : Forward(next), BidirektionalIterator(next, prev), RandomAccessIterator(nex(k))


* Container : Sequence
* Container : Sequence                                   # Array





Revision as of 18:32, 16 June 2008


Generzität :

Algortihmen und Datenstrukturen so zu entwerfen und implementieren, dass sie möglichst
vielvältig verwendbar sind.

Gemeint sind :

  • verschiedene Anwendungen
  • mit vielen Kombinationsmöglichkeiten
  • als wiederverwendbare Bibliothek

--> ohne Neuimplemenation

  • Code austauschen in Bibliotheken


Beispiel : Kopieren eines Containers


def copyArray(a):
  r =[]
  for k in a
  r.append(k)
return k
class Node :
 def__init__(self,data,next)
    self.data = data
    self.next = next
 return k
def copyArrayToList(a) :
   if len(a) == 0 : return None
      first = last = Node (a[0], None)
   for k in a[1:]  :
      last.next = Node(k, None)
      last = last.next


def copyListToArray(l):
    r = []
    while l is not in None :
        r.append(l.data)
        l = l.next
    return r


Beobachtung :

Für N Datenstrukuren ist der Implementaionsaufwand <math>O({N^2})</math>. Alle Funktionen machen das gleiche mit uninteressanten Unterschied


Verbesserung durch Verallgemeinerung zweier Aspekte :

  • Navigation durch die Quelldaten
  • Aufbauen der Zieldatenstruktur


Vereinheitlichung der Zieldatenstruktur :

  • standardisierte Funktion "append"
  • Array hat sie schon
  • Liste : definiere Klasse DoublyLinkedList


class SentinelTag : pass     # keine Daten

class DoublyLinkedNode:
 def__init__(self,data = sentinelTag(), next = None)
      self.data =data
      if next is None:
            self.prev = self.next = self
      else:
            self.next = next
            self.prev = next.prev
            next.prev.next = self
            next.prev = self
def isSentinel(self) : return isinstance(self.data, SentinelTag)


class DoublyLinkedList :  # Realisiert doppelt verbundene kreisförmige Kette mit Seninel als Anker
  
      def__init__(self):
           self.sentinel = DoublyLinkedNode()
           self.size = 0
      def__len__(self): return self.size   #len(l)
      def append(self, value):
          DoublyLinkedNode(value, self.sentinel)
          self.size += size
 
      def__iter__(self):
           return ListIterator(self.sentinel.next)
      
      def reverseIterator(self):
            return ListIterator(self.sentinel.prev)


2. Navigation in der Quelldatenstruktur(Iteratoren) soll
für alle Datenstrukturen funktionieren

  • Objekt, dass auf ein Element des Containers zeigt
  • Zum nächsten Element weiter rücken kann
  • anzeigt, wenn das Ende der Sequenz erreicht ist


def genericCopy(quelle, ziele) :
      for k in quelle :
            ziel.append(k)
  return ziel


liste = genericCopy(array, DoublyLinkedList())       # Statt copyArrayToList
array2 = genericCopy(array,[])                       # Statt copyArray 
array3 = genericCopy(liste,[])                       # Statt copyListToArray 


class ListIterator:
   def__init__(self, node):
       self.node = node
   def next(self):
       if self.node.isSentinel():
          raise StopIteraion()       #Python Konvention
       v = self.node.data
       self.node = self.node.next    # zeigt Ende der Sequenz
       return v                      # Pythonkonvention, gebe vorigen Wert zurück
   def__iter__(self):
      return ListIterator(self.node) # Pythonkonvention, Kopie des Iterators erzeugen

besser stattdessen :

     self__class__(self.node)


Was tut Python bei " for k in quelle":

iter = quelle__iter__()
try :
       while True :
             k = iter.next()
             ...           # Schleifeninhalt
except StopIteration: pass


Rückwärts kopieren :

class ReverseListIterator(ListIterator)
  def next(self):
        if self.node isSentinel(): raise StopIteration()
      v = self.node.data
      self.node = self.node.prev
      return v


revArray = genericCopy(list, reverseIter(), []),
revList = genericCopy(reversed(array), DoublyLinkedList())


Verallgemeinerung auf Funktionen die " etwas tun":

def sumArray(a):
        s = 0
        for k in a :
            s+=a       # s = add(s,k)
      return s 


def maxList(l):
   m = -1111111111111111
   while not l isSentinel:
        m = max(m, l.data)                    # max ist eingebaute Funkion in Python
        l =l.next


Zur Verallgemeinerung werden Funktoren eingerichtet:

  • Funktor muss "callable" sein : falls f Funktor ist, funktioniert v = f(a1, a2,...)
  • Funktion, oder Objekt bei dem die Funktion __call___ definiert ist.


def doSomethingGeneric(functor,iterator, intial):
      for k in iterator
            initial = functor(initial, k)
   return initial

Statt maxList:

m = doSomethingGeneric(max,list -11111111111)  

Statt sumArray :

def add(x,y): return x + y
  s = doSomethingGeneric(add, array,o)

Statt genericCopy :

def append(x,y):
     x.append(y)
   return x
array4 = doSomethingGeneric(append, array[])

doSomethingGeneric() gibt es in vielen Programmiersprachen

   *in Python : reduce     
   *in C++ : accumulate
    ...funktionale Sprachen (Lisp, Haskell...)

verwandte generische Funktionen

map: 

[x1, x2,...] --> [f(x1),f(x2),...] # Funktor mit einem Argument


Offered Interface versus Required Interface

Interface:

  • standardisierte Schnittstelle zwischen Algorithmen und Datenstruktur


Offered Interface:

  • Funktionalität, die eine Datenstruktur anbietet.
  • Die Datensruktur sollte möglichst vielseitig sein.

z.B. PythonList:

  • dynamisches Array
  • stack
  • deque
  • linkedList
  • standardisiert durch abstrakte Datentypen


Required Interface:

  • Funktionalität, die Algorihmus benutzt
  • das required Interface ist meist weniger als das offered Interface

z.B.:

RI lesender Zugriff OI lesender Zugriff schreibender Zugriff Konstruktor remove...


  • standardisiert über Konzepte
  • ADT sind Sammlungen zusammengehörender Konzepte
  • RI sollten minimal sein


Konzepte ( + Hierarchie)

  • copy Constructible ( P: copy.deepcopy)
  • Default Constructible (v1 = v.__class__() ist aufrufbar ) # DoublylinkedNode
  • EqualityComparable('=='), LessThanComparable('<')
  • ThreeWayComparable(__cmp__ ist aufrufbar)
  • Indexable("a[k]", k ist Integer)
  • Mapping("a[key]", key ist arbitrary)
  • Hashable(__hash__ für key)


  • Iteratoren : Forward(next), BidirektionalIterator(next, prev), RandomAccessIterator(nex(k))



  • Container : Sequence # Array


Mathematische Konzepte :

Addable(__add__)
Subtractable(__sub__)
Multiplyable(__mul__)
Dividable(__div__)



Ein offered Interface is mehr als ein required Interface.