2011-12-14 8 views
9

Ho una lista e voglio applicare un test logico a ciascun elemento, e se uno di essi non soddisfa questa condizione, restituire false. Voglio scrivere questo in Mathematica o trovare una funzione built-in, ma sembra che lo ForAll in realtà non lo faccia.Come eseguire test logici per tutti gli elementi di lista in matematica

La mia domanda è: come fare questo in modo più efficiente?

Bonus: che ne dite di una funzione simile per la funzione Exists: ad esempio, se c'è qualche elemento nell'elenco che soddisfa la condizione, restituisce true.

+0

Forse stai cercando And e/o Or? (Mi piace il modo in cui suona, ma potrebbe apparire migliore come (&&)^2 (||)^2) For All ed Exists in realtà non sono pensati per questo sebbene possano essere adattati. Esempio: Risolvi [ForAll [x, x == 1 || x == 2 || x == 3, x> 2.5]] restituirà False. –

+1

Questa domanda è stata posta prima qui, in realtà più di una volta. Vedi qui: http://stackoverflow.com/questions/4181470/custom-function-with-non-standard-evaluation-behaves-like-table, e qui: http://stackoverflow.com/questions/4911827/non- standard-evaluation-and-packedarray –

risposta

9

La risposta alla prima parte della tua domanda potrebbe essere qualcosa in queste righe:

forAll[list_, cond_] := Select[list, ! [email protected]# &, 1] === {}; 

che viene utilizzato in questo modo:

forAll[{1, 2, 3, 3.5}, IntegerQ] 

Il "esiste" la funzione è già implementato nativamente come MemberQ.Si potrebbe reimplementata come:

exists[list_,cond_] := Select[list, cond, 1] =!= {}; 

utilizzarlo come

exists[[email protected], (10 == # &)] 

che restituisce vero come 10 è un elemento che causa il Select per tornare {10} che non è uguale a {}.

+0

Accidenti. Stavo per pubblicare una risposta quando ho capito che era la stessa cosa esatta che hai postato. –

+0

Questa è una scelta molto veloce, forse dovresti deselezionare la mia risposta per un po 'e vedere se gli altri riescono a fare di meglio :). Inoltre, ho solo risposto alla seconda parte della tua domanda, anche se con un po 'di correzione (corretta) puoi anche rispondere alla prima parte della domanda. – nixeagle

+0

Sì, ecco perché l'ho rimosso una volta che ho capito che non rispondeva correttamente alla domanda. E usare 'Length' dopo aver raccolto l'elenco completo di elementi non è affatto efficiente. – nixeagle

8

Questa risposta non è destinato a mostrare il più efficiente metodo , ma piuttosto un metodo alternativo che serve allo scopo pedagogico di mostrare alcune funzionalità di base importante Mathematica.

La risposta di nixeagle evita di testare esplicitamente ogni elemento dell'elenco. Se il test non si presta all'inserimento nel terzo argomento di Select, il seguente potrebbe essere utile.

Per fare questo, è necessario conoscere lo standard Or e And funzioni, così come i comandi Map (/@) e Apply (@@) che sono estremamente importanti per qualsiasi utente Mathematica per imparare. (vedi this tutorial)

Ecco un semplice esempio.

In[2]:= data = RandomInteger[{0, 10}, {10}] 

Out[2]= {10, 1, 0, 10, 1, 5, 2, 2, 4, 1} 

In[4]:= # > 5 & /@ data 

Out[4]= {True, False, False, True, False, False, False, False, False, \ 
False} 

In[6]:= And @@ (# > 5 & /@ data) 

Out[6]= False 

Che cosa sta succedendo qui è che si sta mappando la funzione ("maggiore di 5") per ogni elemento della lista usando Map, per ottenere un elenco di Vero/Falso valori. Si sta quindi applicando la funzione logica standard And all'intero elenco per ottenere il singolo valore booleano.

Queste sono tutte funzionalità fondamentali in Mathematica e vi consiglio di leggere attentamente la documentazione per queste funzioni e di esercitarvi ad usarle.

Questo non è il metodo più efficiente, ma per piccoli problemi non noterai la differenza.

In[11]:= Do[Select[data, ! # > 5 &, 1] === {}, {10000}] // Timing 

Out[11]= {0.031, Null} 

In[12]:= Do[And @@ (# > 5 & /@ data);, {10000}] // Timing 

Out[12]= {0.11, Null} 

Per Exists, l'alternativa al Select sarebbe MatchQ per modelli o MemberQ per i valori espliciti. La documentazione ha alcuni esempi utili.

+0

+1 per mostrare un modo alternativo per farlo :). – nixeagle

+0

Questo non va bene. * Tutti gli elementi * sono testati anche se il primo fallisce. –

+0

@ Mr.Wizard Questo problema è stato affrontato per intero nelle precedenti incarnazioni di questa domanda (che è un duplicato. Peccato che l'abbia visto solo ora) - qui: http://stackoverflow.com/questions/4181470/custom- function-with-non-standard-evaluation-behaves-like-table, e qui: http://stackoverflow.com/questions/4911827/non-standard-evaluation-and-packedarray –

0

nixeagle ha ottenuto la parte di bonus, ma il modo in cui avrei fatto la prima parte è la seguente:

AllSatisfy[expr_, cond_] := [email protected][expr, cond] == [email protected] 
4

da non prendere troppo sul serio, ma questo

ClearAll[existsC]; 
existsC[cond_] := With[ 
    {c = cond}, 
    Compile[ 
    {{l, _Integer, 1}}, 
    Module[ 
    {flag = False, len = [email protected]}, 
    Do[ 
    If[cond[l[[i]]], 
     flag = True; Break[]; 
     ];, 
    {i, 1, len}]; 
    flag 
    ], 
    CompilationTarget -> "C" 
    ] 
    ] 

sembra essere circa 300 volte più veloce delle soluzioni nixeagle's sulla mia macchina. Ciò che fa è emettere una funzione compilata che prende una lista e confronta i suoi elementi con la condizione data (fissata in fase di compilazione), restituendo True se qualcuno di essi corrisponde.

È usato come segue: Compilare con l'appropriato cond, ad esempio

t = existsC[# == 99999 &]; 

e poi

t[[email protected]] // timeIt 

rendimenti 2.33376*10^-6 (uno scenario peggiore, come sto solo cercando in modo lineare e la elemento di corrispondenza è alla fine) mentre

exists[[email protected], (99999 == # &)] // timeIt 

restituisce 0.000237162 (qui, timeIt è this).

+0

+1 per mostrare un modo davvero interessante di usare 'Compile' e farmi pensare a' (defmacro ...) 'in Common Lisp! Questo è probabilmente il mio primo * interessante * incontro con quello che alcune persone chiamano * Mathematica * programmazione "meta". E sì, mi piacerebbe sapere perché "WVM" è più veloce. Finalmente per non smorzare la pura * awesomeness * di questa risposta ... ma sospetto fortemente che questo sia valido solo per i numeri, non per i simboli o per qualsiasi altra cosa con cui '' Compile' '' non funziona (anche se vorrei che funzionasse con più cose !). – nixeagle

+0

@nixeagle grazie! hai ragione, non funzionerà con elenchi di oggetti non supportati da 'Compile', o con elenchi disomogenei ecc. – acl

+0

+1. Non hai bisogno del 'With' esterno - le regole (parameter-passing) hanno (quasi) la stessa semantica e possono anche essere usate per iniettare cose. Per quanto riguarda i tempi, sulla mia macchina il codice C-compilato è molto più veloce di WVM - compilato (come ci aspetteremmo), che contraddice la tua osservazione. –

1

Anche se && e || eseguire la valutazione di corto circuito, vale a dire, non valutare i loro argomenti inutilmente, ho il sospetto che le soluzioni basate su Select[] o Map[] non beneficeranno molto da questo. Questo perché applicano il test logico a ogni elemento, creando un elenco di valori di verità booleani prima dello eseguendo la congiunzione/disgiunzione tra di essi. Se il test che hai specificato è lento, può essere un vero e proprio collo di bottiglia.

Così qui è una variante che fa circuit la valutazione della condizione pure:

allSatisfy[list_, cond_] := 
    Catch[Fold[If[cond[#2], True, Throw[False]] &, True, list]] 

Testing se ogni elemento nell'elenco soddisfa la condizione è ben simmetrica:

anySatisfy[list_, cond_] := 
    Catch[Fold[If[cond[#2], Throw[True], False] &, False, list]] 

Di Naturalmente questo potrebbe essere stato fatto (e candidamente parlando, più facilmente) usando cicli procedurali come While[], ma ho un debole per la programmazione funzionale! approccio basato

+1

Vorrei usare eccezioni etichettate che sono più sicure. Per un'implementazione che lo utilizza, ma è comunque simile al tuo suggerimento, vedi la seconda parte della mia risposta qui: http://stackoverflow.com/questions/4911827/non-standard-evaluation-and-packedarray –

+1

Il terzo argomento di ' Select' consente di "cortocircuitare" il test dopo la prima partita. –

+0

@ Mr.Wizard Questo è un buon punto. –

4

Un modello:

forAll[list_, test_] := MatchQ[ list, _[__?test] ] 

MemberQ implementa già esiste.


Mathematica 10 ha una nuova funzione per questo: AllTrue. Quando tutti gli elementi passano il test di mia funzione sembra essere un po 'più veloce:

a = Range[2, 1*^7, 2]; 

AllTrue[a, EvenQ] // Timing // First 
forAll[a, EvenQ] // Timing // First 
1.014007 

0.936006 

Tuttavia, con un'uscita in anticipo il beneficio della nuova funzione diventa evidente:

a[[123456]] = 1; 

AllTrue[a, EvenQ] // Timing // First 
forAll[a, EvenQ] // Timing // First 
0.031200 

0.265202 
0

Là è una soluzione semplice:

In[1401]:= a = {1, 2, 3} 

Out[1401]= {1, 2, 3} 

In[1398]:= Boole[Thread[a[[2]] == a]] 

Out[1398]= {0, 1, 0} 

In[1400]:= Boole[Thread[a[[2]] >= a]] 

Out[1400]= {1, 1, 0} 

In[1402]:= Boole[Thread[a[[2]] != a]] 

Out[1402]= {1, 0, 1} 

Successo!

Problemi correlati