You are here
Home > posts

Thomas Nield.

Thomas Nield.

Tilfeldige tanker om analyse, forretningsteknologi og andre musings.

Onsdag 3. januar 2018.

Kotlin og line r programmering del I – bin r programmering.

I november 2017 snakket jeg pa KotlinConf og foreslo Kotlin som datavitenskapsplattform. Da jeg planla kodedeksemplene for presentasjonen, var det mange emner a velge mellom. Et vanlig eksempel ville v re en & # 8220; classic & # 8221; maskinl ringslosning som behandler bilder, tekst eller tale med et neuralt nettverk. Jeg kunne nok ha gjort noe med TensorFlow som utvilsomt ville v rt kult.

Men like fascinerende som datavitenskapsomradet er, folte jeg sterkt behovet for a gjore noe annet. Jeg onsket a presentere et emne som er sv rt relevant og av ukjente grunner blir skygget. Jeg onsket a presentere noe praktisk, tilgjengelig og spennende nyttig alt pa samme tid, noe som ville v re spesielt hensiktsmessig for en Kotlin-begivenhet. Det er derfor jeg valgte line r / heltall programmering og presenterte et sjaforplanlegging eksempel ved a bruke Kotlin og ojAlgo.

Line r programmering (ogsa kalt line r optimalisering) er et anvendt matematikkfelt som ofte brukes i operasjonsforskning og planlegging. Det forsoker a finne en optimal losning pa et planleggingsproblem nar et sett med forretningsbetingelser eksisterer. Noen omrader hvor line r programmering er kritisk, er:

Transportnettverk (flyselskaper, tog, bakken, osv.) Personellplanlegging (sykepleiere, leger, arbeidere, l rere) Ressursplanlegging (klasserom planlegging, produksjon, oppdrett, forsyningskjede ledelse) Produktblanding (finansielle portefoljer, ingrediensblanding osv.) Spill og # 8220, AI & # 8221; (sudoku, sjakk, tic-tac-toe, etc)

Nar du horer et forretningsproblem som inneholder mal som sier «minimalisere», «maksimere», eller bare finne en losning som er mulig, kan du gjore det mer kortfattet, «# ~» , line r programmering bor komme rett ut av verktoysettet. Faktisk kan det sies at tvangslosning er en form for maskinl ring. I mange situasjoner kan det til og med v re en bedre tiln rming enn nevrale nettverk eller andre former for AI.

Linj r programmering er en rolig underdog og arbeidshorse, som brukes tungt i driftsdrevne bransjer med liten fanfare. Kanskje jeg har forstyrrelser siden jeg jobber for et flyselskap, men det overrasker meg hvor lite oppmerksomhet det blir. Selv for forbruker mobile apps, er det et bredt spekter av apps som aldri har blitt utforsket. For eksempel, hvor mange mobilapper er det som automatisk planlegger skift av personalet? Det er sikkert store, dyre bedriftsapplikasjoner der ute, men jeg har ikke sett en $ 5 Android-app som gjor dette.

Line r vs Integer vs Blandet Programmering.

& # 8220; Linear & # 8221; betyr kontinuerlig, noe som mer eller mindre betyr at en variabel kan loses som en desimalverdi. Hvis jeg planlegger en arbeidstaker for en bestemt dag, kan den optimale skiftstart lose til 12, 12,5 timer og til og med 12,5000012 timer. Tallet far lov til a flyte fritt hvor som helst pa en kontinuerlig talelinje, i stedet for a bruke faste hele tall. Ren line r programmering kan v re onskelig for «blandingsproblemer», som for eksempel matredienser eller finansiell portefoljeoptimalisering.

For planlegging problemer, er imidlertid ren line r programmering ikke nok. Skift blir ofte modellert som diskrete & # 8220; slots & # 8221; som kan representeres med hele tall. For eksempel kan jeg ha en 12-timers dag, og jeg ma tildele arbeidere for den dagen. Jeg kunne vilkarlig bestemme et & # 8220; –spor & # 8221; er 1 time, noe som vil resultere i 12 spor. Jeg kunne lage et spor 4 timer, noe som ville resultere i 3 spor eller & # 8220; skift & # 8221 ;. Min modell beskriver deretter problemet som «Slot1, Slot2, Slot3 & # 8221; & # 8230; og sa videre. Dette er kjent som heltall, eller & # 8220; diskret & # 8221; optimalisering.

Hvis du ikke onsker a optimalisere med partielle enheter, er helhetsprogrammering ogsa nyttig for den situasjonen. For eksempel vil jeg kanskje ikke produsere 100.5002 enheter av et produkt. Det ma v re et helt tall som 100 eller 101. Heltall programmering brukes ogsa ofte for bin r / boolsk logikk ved a begrense en variabel til 1 eller 0, noe som jeg vil fokusere tungt pa i dette blogginnlegget.

Du kan blande line r og heltall programmering, og dette kalles blandet heltall programmering & # 8221 ;. Dette betyr i utgangspunktet at noen variabler som er lost, far lov til a v re kontinuerlig, mens andre kan v re heltall. Sjaforproblemet jeg presenterte hos KotlinConf var et blandet problem, da forerskiftet start / slutt var kontinuerlig, men for a hindre overlapping brukte jeg bin re variabler som kunne v re 1 eller 0.

Men igjen i dette blogginnlegget kommer jeg til a fokusere tungt pa bin r optimalisering. Jeg haper a gjore en serie blogginnlegg pa line r programmering og optimalisering, men jeg tror dette vil gjore et godt forste emne.

Komme i gang.

For a holde konsepter fokusert og enkelt, skal jeg presentere et abstrakt problem. Men dette kan brukes til ekte eksempler, spesielt for planlegging av applikasjoner. Jeg skal bruke Kotlin og ojAlgo, sa sorg for a konfigurere bade i Maven / Gradle-avhengighetene.

For vi dykker inn, legg ogsa disse hjelpefunksjonene til ojAlgo til a fungere som en improvisert DSL. Vi vil ogsa instantiere en ExpressionsBasedModel, og vare hjelperfunksjoner vil automatisk navngi variabler og funksjoner for du legger dem til det.

Et abstrakt eksempel.

Si at vi har fem bokstaver: A, B, C, D og E. La ‘s representere dette som en Kotlin-tallbar.

La na la opp fem numre: ONE, TWO, THREE, FOUR og FIVE. Vennligst ikke forveksle dette med Java-nummertypen. Vi definerer var egen. Verdien eiendom vil holde sin int motpart.

Dette monsteret vi skal l re er nyttig og kan brukes til a tilordne universitets klasser, skift av ansattes tidsplaner, etc. For eksempel kan Letter representere en ansatt, og tallet kan v re et skifte. Men la oss beholde dette abstrakte for na.

Si at vi vil tilordne hvert brev til et nummer, men det kan bare tildeles en gang. Na kan vi bare gjore dette med en zip () operasjon, men vi skal gjore dette problemet underlagt ytterligere begrensninger og regler senere. La oss derfor gjore dette matematisk, og vi vil bygge videre pa det fundamentet.

Forestille et rutenett mye som det brettspillet Battleship hvor en akse er hver Letter og den andre er hver nummer. Krysset mellom hver bokstav eller tall vil v re en 1 eller 0 (sann eller falsk), som indikerer om bokstaven ble tildelt det nummeret. Her er en mulig losning gjort visuelt:

B r med meg. La ‘s representere hvert kryss og & # 8221; som en Slot klasse, som holder det gitt Letter og Number. Vi vil ogsa opprette en ojAlgo-variabel som er bin r, noe som betyr at den er begrenset til a v re 1 eller 0. Vi vil ogsa opprette et folgesvennobjekt for a bygge og holde alle forekomster vist i dette rutenettet.

Hvordan handhever du matematisk et brev som bare blir tildelt et nummer en gang, og omvendt? Lett! For a se om et brev bare har blitt tilordnet en gang, summere bare hele sitt & # 8220; –spor & # 8221; verdier og handheve at den ikke ma v re storre enn 1. Visuelt ma alle verdiene i en gitt kolonne eller en gitt rad ikke overstige 1. Matematisk vil dette bli uttrykt som dette:

Vi kunne ogsa bruke = i stedet for & lt; =, men hvis vi noen gang hadde flere tall enn bokstaver, ville det v re bra med ingen oppgave som skjer i det hele tatt. Vi vil bare ikke ha det tildelt mer enn en gang.

Gjor det samme for hvert nummer. For eksempel ma ONE ‘s slots summe til ikke mer enn 1.

For a utfore denne enkle logikken, endre brevet og nummerklassen for a hente sine spor. Deretter vil vi legge til en addConstraints () -funksjon til hver, der vi vil ringe addExpression (), sette ovre () til 1, og deretter lokke gjennom hvert spor til a legge til & # 8221; dens variabel. Siden vi ikke trenger a multiplisere hver variabel med en koeffisient, bare sett den til 1 som multiplikasjon 1, har ingen effekt.

Hvis denne set () -funksjonen forvirrer deg, er vi i utgangspunktet bare multipliserer hvert bin r med 1 som ikke har noen effekt.

La na la dette ga. Vi vil ga gjennom hvert brev og nummer for a ringe funksjonen addConstraints (). Vi prover ikke a minimere () eller maksimere () noe (som fortjeneste eller kostnad) i dette problemet. Vi vil bare ha noe som er operativt og fungerer med alle begrensninger vi definerte. Da vil vi skrive ut et pent rutenett av alle vare resultater.

Her er produksjonen jeg fikk:

Som du kan se, fikk vi et OPTIMAL resultat, noe som betyr at det fant en losning (i motsetning til en ufeilbarlig hvis ingen losning er mulig med vare begrensninger). Som du ser i vart improviserte konsollrutenett, ble hvert brev tildelt (via en 1) til et nummer.

La na hoppe dette opp et hakk.

Begrensning av gjenstander til bestemte omrader.

Si at to tilleggsregler ma legges til var modell:

C ma tilordnes et tall som er storre enn eller lik tre T ma tildeles et tall mindre enn eller lik TWO.

Disse faste begrensningene er vanligvis ikke vanskelig a implementere. Det er nar vi begynner a gjore variabler i forhold til andre variabler at ting begynner a bli gnarly (dekket senere i denne artikkelen). Men for disse to reglene er alt vi trenger a gjore, a plage sporene i de onskede omradene, og si at de ma summe til 1.

Vi kan legge disse to begrensningene til modellen var, og minst en av disse slissene for henholdsvis C og D ma v re 1 for de ligningene som gir sann. La oss bare gjore dette i var hovedfunksjon (). Vi skal bruke niva () i stedet for ovre () dette for a uttrykke en streng = heller enn en & lt; =.

Nar vi kjorer dette, vet vi nok at vi far en utgang som samsvarer med de to nye reglene:

Ok, la eskalere dette til noe mer realistisk.

Bruke flere pafolgende blokker.

Nar du begynner a handtere relativ begrensning, er det her ting blir mindre intuitive. Linj r og heltall programmering begrenser deg til bare a uttrykke funksjoner i en enkel tilleggs / subtraksjon struktur som Ax + By + Cz spor. Dette er realistisk som klasserom, personale og andre planleggingsproblemer kan bryte skift opp til si, 15 minutters blokker, og et klasserom kan planlegges i 90 minutter (eller 6 blokker). I sa fall legger du til folgende regler:

Letter B krever 2 sammenhengende spor. Letter C krever 3 sammenhengende spor.

Det forste vi ma gjore er a legge til flere nummerelementer, ettersom vi ikke har nok til disse nye kravene. La ‘s legge hele veien opp til NINE, selv om det faktisk er mer enn vi trenger (bare fordi).

Sa hvordan i verden uttrykker vi denne logikken av flere sammenhengende blokker som en line r funksjon? Det er ikke intuitivt, sa det beste stedet a starte er a prove a gjore det intuitivt. La ‘s plott med blyant og papir fa noen gyldige scenarier for det vi onsker. Her er et eksempel pa et onsket scenario:

La fokusere bare pa rad for C. Siden C krever tre sammenhengende spor, la & # 8217; s bryte ned et gitt tilfelle i rullende grupper pa tre som dette:

Na har vi rullende grupper pa tre spor. GRUPPE 6 har det onskede settet av tre sammenhengende 1’en. La etiketten hver av disse gruppene ha en RESULT-kolonne, der 1 indikerer en suksess og 0 indikerer en feil som dette:

Sa det vi virkelig onsker er en serie begrensninger uttrykt som disse ligningene:

Vel det eskalerte raskt. Na for du kaster inn handkleet, studer virkelig hva som skjer over og gi det sjansen til a synke inn. Trekk ut en blyant og papir hvis du trenger og bevis noen tilfeller. Igjen brot vi C’s spor i sammenhengende, rullende grupper pa tre. En gruppe ma resultere i en 1 mens resten ma v re en 0. Serien av funksjoner ovenfor uttrykker dette. Vi lager en ny bin r variabel for hver gruppe som kan v re 1 eller 0. Vi legger da sammen alle disse bin rene som skal summe til 1, noe som betyr at bare en av dem ma v re 1 mens resten er 0.

M vil faktisk v re 3 i dette tilfellet, fordi vi trenger tre spor. Vi multipliserer det til gruppens bin re og trekker det som en subtil mate a utfore en begrensning pa. Dette uttrykket ma v re storre enn eller lik 0, og at M kan eller ikke kan bli ugyldig dersom gruppens bin re er 1 eller 0. Hvis vi har 1 spredt over flere grupper, vil hele systemet av ligninger ugyldiggjore dette tilfellet. Hvis det finnes tre sammenhengende 1 & # 8217; s i en gruppe, vil det tilfredsstille systemet med ligninger.

Slik uttrykker vi dette i var Kotlin-modell:

Nar du kjorer dette, er du sikker nok til at du far sammenhengende sett med spor for B og C.

Her er all koden i sin helhet. Du kan ogsa klone koden fra GitHub.

Konklusjoner.

Linj r programmering er ganske enkelt a modellere i de fleste tilfeller, men som du kan se her kan hel / bin r programmering v re vanskelig. Jeg l rer fortsatt bin re monstre til denne dagen, og finner det nyttig a bruke mye tid med blyant og papir som eksperimenterer med ligninger. Jeg synes det er en hit-eller-miss-prosess med mye bevisarbeid, og jeg haper a bli dyktig i a takle enda storre virkelige problemer.

Heldigvis gjorde Kotlin det enkelt, organisert og refactorable a utfore, og tillot oss a bruke mer tid pa a tenke pa matematikken. Som du sikkert har lagt merke til, kom Kotlin stdlib utrolig praktisk til a forberede data til modellen.

Hvis du har a gjore med tusenvis av variabler, kan du stote pa ytelsesproblemer, selv med ojAlgo. Heldigvis stotter de fleste losere, inkludert ojAlgo, plugging i kommersielle optimaliserings-implementeringer som CPLEX. Nar loseren din opptrer utmattet eller sakte, og du er sikker pa at det ikke er noen modelleringsfeil, kan det v re verdt a fa en kommersiell losning.

I de kommende fa manedene vil jeg gjore noen flere innlegg om bruk av Kotlin for line r / heltall programmering og optimalisering. Inntil da, sorg for a sjekke ut denne boken, sa vel som denne. Sorg ogsa for a bruke Math Stack Exchange for spesifikke modelleringssporsmal, og StackOverflow for ojAlgo-sporsmal.

Top

Hallo! Vil du spille i det mest populære kasinoet? Vi fant det for deg. Gå her nå!